home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #2 / Monster Media No. 2 (Monster Media)(1994).ISO / prog_gen / ada_tutr.zip / ADA_TUTR.DAT < prev    next >
Text File  |  1994-08-22  |  338KB  |  1 lines

  1.  122 608  D!  IN  MJ  PA  ]`  `@  j>  o.  sI  yI  ~P !$> !(; !/R !4D !86 !>. !B# !E` !IE !NL !U\ !g^ !sB !|S ".) "8D "@8 "Q_ "c_Q"mG "tE "vV "}. #!4Q#'' #9K #@KQ#GT #JK #ND #RJ #Z> #j# #yL $)S $7PQ$D3 $H3 $KP $ODQ$S[ $WC $[- $_, $c@ $p/ $x: %(<Q%82 %<I %C% %FF %IW %N% %R6 %V> %eN %sY &$F &7.Q&F< &M` &UL &\P &cH &lI &t? '!G '3MQ'D1 'F> 'KY 'Q, 'b\A'q7 (#; (.5 (56 (C^ (ZGQ(pU (sF (uK (x1 )!' )/2 )>6Q)N^ )U1 )ZL )b/ )oT )}< *3HQ*E# *J( *R5 *W\ *^" *d( *t& *}` +1OQ+FX +J7 +M= +P7 +`/ +o^Q+}! ,$9 ,&@ ,)T ,,6 ,.S ,2; ,4X ,<N ,KU ,WH ,eDQ,o. ,s1 ,v5 ,zH -"- -,2 -9Q -LJQ-X5 -^P -bF -f. -sU .%@ .3BQ.>G .EV .K< .PE .W. .\Z .a^ .kC .qU /$&Q/81 /=' /B. /GS /OF /]; /k!Q/u% /z6 /~L 0#( 0(" 08TQ0B\ 0L" 0U_ 0^F 0fW 0sX 0~)A1,X 1A: 1P@ 1\R 1i2 1sN 1}- 2,G 24; 2A4 2R?Q2^H 2g@ 2j( 2lS 2oU 2r< 3&A 35^ 3DK 3LW 3][Q3n2 3y* 4%8 4.G 49" 4D# 4RR 4bA 4s4 5&.Q5+` 52X 58G 5=Y 5ES 5U6 5bE 5p< 6(.Q62R 6:$ 6I. 6U/ 6]= 6e: 6p# 6w# 7 L 7+OA7=S 7KF 7[M 7hG 7{W 8)/ 87U 8?K 8M\ 8]N 8lRQ8|^ 9(& 92; 9<E 9GS 9TI 9gR 9w/A:&I :6< :<^ :J* :WK :_A :kK :w' :|[ ;''Q;84 ;=Z ;H( ;PX ;W! ;\B ;eN ;kN ;|E <.,Q<:^ <>_ <E% <I( <MM <\1 <g- <w` ="EQ=0V =74 =>6 =E/ =S% =dO =nG =u=Q>'+ >18 >=/ >G, >PU >\. >l=Q>{\ ?#J ?*7 ?/# ?B6 ?NR ?Y2 ?hRQ?yA ?}! @!> @$Z @0S @?J @I@ @TY @a,Q@o. @t4 @{@ A#1 A6C AC! AL4 AW?QAd) AoM A{G B(" B7" BEX BMQ B]- Bp* C&' C51 CFS CQN C``QCl\ CrK Cx< C~! D1" D:*QDHZ DM_ DUE D[C D`O De[ Dm8 Dx. E"S E*] E=H EK0 EX\QE_H Ej7 EmO Eq* EsZ E{S F-I F>- FG6QF_9 FdF Fg\ Fk4 FnL Fq? FtX G X G), G@5 GQYQG_/ Gf% GkV Gq3 H$_ H:V HK0 HVSQH`" Hc5 Hf" Hi- Hl8AHnU I&, I-K I4% I@? IL8 IX] Ib) Ii` Iw^ J0W JA5 JU5 J]=QJ`^ JhN JrS J{N K&' K/O K>Z KKA KY[ KhGQKvR K}V L'5 L/E L8E L@C LFP LSU L`& Lh=QLsR M + M+0 M5[ M>A MEW MQ-AM_" MnQ MyO N'' N-O N5G NBU NQY N^UQNhI NqF NzM O&' O0* O9) OFQ OWD ObD Ol] Ox3 P#P P,^ P7' PEP POL P`U PnU Pz_ Q'1 Q4KQQ@& QDJ QHU QM. QQB QUS Q]J QnM Q~. R4' R<7QRJ\ RNA RRW RUN RX8 Rl% S$S S07 SD%QSRR SY5 Sa_ Sh9 SnR S~` T/! T=B TJ3 T[SQTgQ Tk* To+ Tr] U"E U5J U=? UOK Ud3QUp4 Us7 UyP U}9 V!A V5T VFT VW. V`P Vm+ Vx. W)Z W4; W<X WKQ WNI                                                                                                                                                                                                        {@-\@T`{@-\ ~@P\ `{@-\ ~@'^C O N G R A T U L A T I O N S !~@(\ `{@-\ ~@P\ `{@-\@T`{{{@&^You've successfully completed ADA-TUTR, the Interactive Ada Tutor.`{{{@1Your comments and suggestions are encouraged.{@>Please send them to:{{@+Software Innovations Technology, Attention: John J. Herro{@01083 Mandarin Drive NE, Palm Bay, FL 32905-4706{{{@@Have a good day!{{{[]{{@:Thank you for using^ADA-TUTR`.{{{@2Please send your comments and suggestions to{{@+Software Innovations Technology, Attention: John J. Herro{@01083 Mandarin Drive NE, Palm Bay, FL 32905-4706{{{@0I hope to see you again soon.  Have a good day!{{{{[]{{{@7The current screen number is$.{{@2You're about# percent through the course.{{{{{@7Do you want to exit^ADA-TUTR~now?{}Please press Y for yes or N for no.[Y102N108B108 108#105M106]~@#\@f`{@$\ ~@b\ `{@$\ ~@7W E L C O M E@#T O@8\ `{@$\ ~@b\ `{@$\ ~@8^A D A - T U T R~@9\ `{@$\ ~@b\ `{@$\ ~@(T H E@#I N T E R A C T I V E@#A D A@#T U T O R@)\ `{@$\ ~@b\ `{@$\@7by John J. Herro, Ph.D.@8`{{@$Software Innovations Technology@1Serial #  14320{@(1083 Mandarin Drive NE@7Version  3.00{@'Palm Bay, FL  32905-4706@722-AUG-1994{@,(407) 951-0233@2Copyright 1988-94 John J. Herro{{@$Shareware: Try^ADA-TUTR~free.  To use it after the free trial, individ-{@$uals must register and organizations must buy a license.  Both are very{@$inexpensive, and give many benefits.  See page 2 of PRINT.ME for infor-{@$mation.  Whether or not you use^ADA-TUTR~and register or buy a license,{@$please copy the complete program and give unmodified copies to others!{{@9Have you used^ADA-TUTR~before?{}@(Please press Y for yes or N for no.  You need not hit ENTER.[Y107N122]{{@3What screen number would you like to see?{{@'(If you don't know, type 106 and I'll take you to the main menu.){{{Please type the number and press ENTER:{[#]@CMAIN MENU{{{%A~ Restart the Program.@1^I~ Subprograms and Packages{{%B~ Introduction@9^J~ Access Types, User Defined Types,{@Oand Derived Types{%C~ The Format of an Ada Program{@H^K~ Exceptions, Text_IO, and{%D~ Generic Instantiation and@3Assignment 5{@&Assignment 1{@H^L~ Generics, Tasking, and Assignment 6{%E~ Simple Declarations and Simple{@&Attributes@8^M~ More Records and Types{{%F~ Operators, Control Constructs, and@#^N~ Advanced Topics{@&Assignment 2{{%G~ Records, Arrays, and Assignment 3{{%H~ Recursion and Assignment 4@+^X~ Exit the Program.{}Please press a letter.[A104B109C110D111E112F113G114H115I116J117K118L119M120N121]{{@@^WELCOME BACK!`{{{{@>Would you like to:{{{@1^1~ Resume where we left off?{{@1^2~ Go back to the last question?{{@1^3~ Go back to the last Outside Assignment?{{@1^4~ Go to the main menu?{{@1^5~ Go to a screen number of your choice?{}Please press 1, 2, 3, 4, or 5.[11002099309841065105 100B100#105M106]{{@>Would you like to:{{{@1^1~ Go back to where we were?{{@1^2~ Go back to the last question?{{@1^3~ Go back to the last Outside Assignment?{{@1^4~ Go to the main menu?{{@1^5~ Go to a screen number of your choice?{}Please press 1, 2, 3, 4, or 5.[11002099309841065105 100B100#105M106]@AINTRODUCTION{@EMENU{{{^A~ Welcome@>^F~ A Very Brief History of Ada{{^B~ Printed Course Notes@1^G~ What is Ada 9X?{{^C~ Do I Need a Textbook for this@(^H~ What's a "Validated" Ada Compiler?{@&Course?{@I^M~ Go Back to the Main Menu.{^D~ Do I Need an Ada Compiler for{@&this Course?{{^E~ What is Ada?@9^X~ Exit the Program.{}Please press a letter.[A122B123C125D126E128F129G130H136M106]@9THE FORMAT OF AN ADA PROGRAM{@EMENU{{{@%^A~ Our First Ada Program@.^F~ Numbers{{@%^B~ Local Declarations@1^G~ Making the Dot Notation{@SAutomatic{@%^C~ Capitalization and Spacing{{@%^D~ Comments@;^M~ Go Back to the Main Menu.{{@%^E~ Identifiers@8^X~ Exit the Program.{}Please press a letter.[A143B145C156D158E159F167G168M106]@4GENERIC INSTANTIATION AND ASSIGNMENT 1{@EMENU{{{@1^A~ Displaying Integers{{@1^B~ Generic Instantiation{{@1^C~ Outside Assignment 1 -{@8Preparing to Run Ada on Your Computer{{@1^D~ The Ada Library{{{@1^M~ Go Back to the Main Menu.{{@1^X~ Exit the Program.{}Please press a letter.[A178B184C186D189M106]@3SIMPLE DECLARATIONS AND SIMPLE ATTRIBUTES{@EMENU{{{@8^A~ Variables and Constants{{@8^B~ Enumeration Types{{@8^C~ Subtypes{{@8^D~ Simple Attributes{{{@8^M~ Go Back to the Main Menu.{{@8^X~ Exit the Program.{}Please press a letter.[A196B202C211D213M106]@0OPERATORS, CONTROL CONSTRUCTS, AND ASSIGNMENT 2{@EMENU{{{@$^A~ Operators@6^H~ Labels and GOTOs{{@$^B~ Range Tests@4^I~ The CASE Construct{{@$^C~ The Short Circuit Forms@(^J~ Brief Overview of Functions{{@$^D~ The IF Block@3^K~ Outside Assignment 2 -{@NExercise in Enumeration Types{@$^E~ WHILE Loops{{@$^F~ FOR Loops@6^M~ Go Back to the Main Menu{{@$^G~ The EXIT Statement@-^X~ Exit the Program.{}Please press a letter.[A229B232C237D245E254F256G262H264I269J275K278M106]@7RECORDS, ARRAYS, AND ASSIGNMENT 3{@EMENU{{{@8^A~ Records{{@8^B~ Arrays{{@8^C~ Multidimensional Arrays{{@8^D~ Strings{{@8^E~ Array Operators{{@8^F~ Outside Assignment 3 -{@?Exercise in Records{{{@8^M~ Go Back to the Main Menu.{{@8^X~ Exit the Program.{}Please press a letter.[A286B294C307D314E327F329M106]@:RECURSION AND ASSIGNMENT 4{@EMENU{{{@8^A~ Recursion{{@8^B~ The Tower of Hanoi Problem{{@8^C~ Outside Assignment 4 -{@?Exercise in Recursion{{{@8^M~ Go Back to the Main Menu.{{@8^X~ Exit the Program.{}Please press a letter.[A336B343C348M106]@;SUBPROGRAMS AND PACKAGES{@EMENU{{{@3^A~ Procedures and Functions{{@3^B~ Default Parameters{{@3^C~ Packages{{@3^D~ Functions with Infix Notation{{@3^E~ Information Hiding: Private Types{{@3^F~ Type Text and Limited Private Types{{@3^G~ Hierarchical Libraries{{{@3^M~ Go Back to the Main Menu.{{@3^X~ Exit the Program.{}Please press a letter.[A353B365C372D380E389F404G420M106]@.ACCESS TYPES, USER DEFINED TYPES, AND DERIVED TYPES{@EMENU{{{@4^A~ Access Types{{@4^B~ User Defined Types and Portability{{@4^C~ Derived Types{{{@4^M~ Go Back to the Main Menu.{{@4^X~ Exit the Program.{}Please press a letter.[A423B446C448M106]@5EXCEPTIONS, TEXT_IO, AND ASSIGNMENT 5{@EMENU{{{@5^A~ Exceptions{{@5^B~ More About Text_IO{{@5^C~ Outside Assignment 5 -{@<Writing a Simple Line Editor{{{@5^M~ Go Back to the Main Menu.{{@5^X~ Exit the Program.{}Please press a letter.[A455B473C483M106]@6GENERICS, TASKING, AND ASSIGNMENT 6{@EMENU{{{@:^A~ Generics{{@:^B~ Tasking{{@:^C~ Outside Assignment 6 -{@@Exercise in Tasking{{{@:^M~ Go Back to the Main Menu.{{@:^X~ Exit the Program.{}Please press a letter.[A491B501C524M106]@<MORE RECORDS AND TYPES{@EMENU{{{@0^A~ Record Discriminants and Record Variants{{@0^B~ Tagged Records and Dynamic Dispatching{{@0^C~ Abstract Types and Abstract Subprograms{{@0^D~ Fixed Point, Modular, and Universal Types{{{@0^M~ Go Back to the Main Menu.{{@0^X~ Exit the Program.{}Please press a letter.[A529B536C546D548M106]@@ADVANCED TOPICS{@EMENU{{{%A~ Renaming@=^H~ Unchecked Conversion and Unchecked{@ODeallocation{%B~ Packages Standard and ASCII{@H^I~ Pragmas{%C~ An Alternative to Infix Notation{@H^J~ Loose Ends and Pitfalls{%D~ More Attributes{{%E~ Sequential_IO and Direct_IO{@H^M~ Go Back to the Main Menu.{%F~ Subprogram Parameters with Generics{{%G~ Representation Clauses and System@$^X~ Exit the Program.{}Please press a letter.[A560B562C564D569E572F578G580H587I590J597M106]@)\@\`{@)\ ~@X\ `{@)\ ~@#^WELCOME TO ADA-TUTR, THE INTERACTIVE ADA TUTOR!~@$\ `{@)\ ~@X\ `{@)\@\`{{%ADA-TUTR~will make you an excellent Ada programmer in minimum time.  You should{be familiar with at least one other high-level language (Basic, Pascal, etc.){{You can study as long as you like. ^WHENEVER YOU WANT TO EXIT THE PROGRAM, JUST{TYPE X.~ (I'll ask you to confirm that you really want to exit, in case you{typed X by mistake.)  I'll remember exactly where we left off, so when you're{ready to learn again, you'll be able to go back there or to any other lesson.{Remember, just type X at any time to exit^ADA-TUTR`.{{%ADA-TUTR~works with monochrome as well as color computers.  Please adjust the{brightness and contrast of your screen now, so that the^highlighted~words are{noticeably brighter than the others, but all are easy to read. ^YOU CAN SET THE{COLORS AT ANY TIME BY TYPING S`, and I'll remember your color choices.{{Please send your comments and suggestions to Software Innovations Technology,{Attention: John J. Herro, 1083 Mandarin Drive NE, Palm Bay, FL 32905-4706.{}Please type a space to go on.  (You need not hit ENTER.)[ 123B104]@>PRINTED COURSE NOTES{{To get the most from^ADA-TUTR`, you should have a printed copy of the PRINT.ME{file.  If you haven't started printing the course notes yet, read this screen{and then type X to exit the program temporarily.  Remember, you can leave{%ADA-TUTR~at any time, and later pick up exactly where you left off.{{Then, when the system prompt (usually^C>`) appears, type:{{@@^PRINT PRINT.ME`{{You can then restart^ADA-TUTR~while your course notes are being printed.{Please read them through page 2 now.  If you got this far, you don't need page{6.  Please read page 42 if you want to install^ADA-TUTR~on a non-PC computer,{such as a workstation or a mainframe.{}Please type X to exit, a space to go on, or B to go back.[ 124B122]In addition to the printed course notes, we recommend (but don't require) that{you have access to the Military Standard Ada Programming Language manual,{ANSI/MIL-STD-1815A, 1983.  This volume is often called the^Language Reference{Manual`, or^LRM`.  You'll probably find it in a public library, or perhaps in{your company library.  If you can borrow an LRM, it's legal to copy the entire{book.  You can also buy an LRM very inexpensively.{{As this is written (August, 1994), a draft copy of the Ada 9X LRM is also{available.{}Please type X to exit, a space to go on, or B to go back.[ 125B123]@5DO I NEED A TEXTBOOK FOR THIS COURSE?{{Although the LRM is a good reference, it's difficult reading and not a good{learning tool.  With^ADA-TUTR~you probably won't need a textbook, but we made a{special arrangement with John Wiley and Sons in case you would like to have a{textbook to go along with this course.  If you copy page 37 of PRINT.ME, or{print the file COUPON.TXT, you can purchase the excellent textbook RENDEZVOUS{WITH ADA by David Naiditch for a very good price.  Be sure to send your order{to the address on the coupon, not to us.{{If you're using a PC and you ever want to print the screen that's currently{being displayed, just hold a Shift key while pressing the^PrtSc~key.{{A few of you asked us for a way to print^all~the screens in this course, so we{added the program^BOOK~to^ADA-TUTR`.  While this is by no means required, or{even recommended, if you want a printout of all the screens, please see page 38{of your printed course notes for instructions on running^BOOK`.  Be prepared to{print about 500 pages!{}b[ 126B124]@3DO I NEED AN ADA COMPILER FOR THIS COURSE?{{An Ada compiler is helpful, but not required.  As we go along, there will be{six Outside Assignments; most of them ask you to write and compile a short Ada{program.  If you don't have access to an Ada compiler, just skip the Outside{Assignments.{{A brief list of Ada compilers available for the PC and compatibles is in your{printed course notes, on page 39.  We tried to include all the popular Ada{compilers, but we might have missed some.  If you know of an Ada compiler that{you think should be on that list, please contact us.{{That's enough discussion of what's recommended for^ADA-TUTR`.  Let's begin!{}b[ 127B125]@;^ADA-TUTR COURSE OUTLINE`{{{%>  INTRODUCTION~@<Recursion and Assignment 4{{@#The Format of an Ada Program@-Subprograms and Packages{{@#Generic Instantiation and@0Access Types, User Defined Types,{@&Assignment 1@=and Derived Types{{@#Simple Declarations and Simple@+Exceptions, Text_IO, and{@&Attributes@?Assignment 5{{@#Operators, Control Constructs, and@'Generics, Tasking, and Assignment 6{@&Assignment 2{@LMore Records and Types{@#Records, Arrays, and Assignment 3{@LAdvanced Topics{}b[ 128B126]@BWHAT IS ADA?{{Ada is a modern language designed for programming large scale and real time{systems.  Ada is also an excellent general purpose language.  It has many new{features which help prevent errors and detect errors earlier.{{However, Ada is much more than a new language.  It's also a new programming{%philosophy`.  Beware of learning just "Ada syntax"; you'll wind up writing{Basic-like (or Pascal-like, etc.) programs that happen to be coded in Ada.  If{you do that, you'll lose the many benefits of Ada.  Unfortunately, you won't{see why Ada is a new programming philosophy until later in this course.  (By{the time we get to packages and information hiding, you'll be an enthusiastic{convert.)  In the meantime, please take our word for it:  Ada is a whole new{programming philosophy, not just another language.{{Because of its many features, Ada is relatively complicated.  There's about{seven times as much to learn as Pascal.  However, the effort pays great{dividends.  Once you learn the language, Ada programs are easier to write,{easier to read, and much easier to modify a month or a year later.{}b[ 129B127]@:A VERY BRIEF HISTORY OF ADA{{Ada was named for Augusta Ada Byron, countess of Lovelace and daughter of the{poet Lord Byron.  She worked with Charles Babbage on his Analytical Engine, and{has been called the world's first programmer.  The Language Reference Manual{(LRM) was given the number ANSI/MIL-STD-1815A because Augusta Ada Byron was{born in 1815.{{Ada was invented because the U.S. Department of Defense (DoD) realized that{none of the existing languages was very suitable for real-time control of{large, embedded systems.  An embedded system is a computer system inside a{product other than a computer, such as an intelligent oven or a guided missile.{Programs for embedded systems are usually written with a^cross compiler`, a{compiler that runs on one machine and produces code for another.  Cross{compilers are often called compilers for short.{{In 1977 the DoD issued a Request for Proposal to develop a new language; the{leading four contenders were designated Blue, Red, Yellow, and Green.{Eventually Green was selected to be Ada; it was designed by the company{Honeywell Bull under the direction of Jean Ichbiah of France.{}b[ 130B128]@@WHAT IS ADA 9X?{{The present version of Ada was standardized in 1983.  For this reason, the{present version of Ada is often called Ada 83.{{As this is written (August, 1994), there's an effort to revise the Ada{language.  Revision should be completed sometime in the 1990's.  For this{reason, the new version of Ada is called Ada 9X.{{ADA-TUTR will point out the differences between Ada 83 and Ada 9X as we go{along.  All of the programs and examples in this course are designed to compile{and run with either an Ada 83 or an Ada 9X system, except for the examples{specifically labeled as Ada 9X only.{}b[ 131B129]In the author's opinion, which^one~of the following statements is true?{{{1.  Ada is simpler than Pascal.{{2.  Although Ada was designed for embedded systems, it makes a good general{@$purpose language.{{3.  Basic and Pascal programs can easily be translated into good Ada programs.{{4.  In languages that are simpler than Ada, errors are usually detected earlier{@$than in Ada.{}Please press 1, 2, 3, or 4, or B to go back.[2132113331344135B130]%You're right!~ Ada makes use of the latest advances in software engineering, so{it makes an excellent general purpose language.{}q[ 136B131Q131]No, Ada is more complicated than Pascal.  So far as the^philosophy~is{concerned, Ada is an extension (or "superset") of Pascal.  However, in^syntax`{Ada isn't a superset of Pascal; the Ada syntax is different.{{Although Ada is more complicated than Pascal (and many other languages), it has{many advantages.  These advantages pay dividends in reduced effort to develop{and maintain programs.{}q[ 136B131Q131]No, it might be easy to translate Basic and Pascal programs into Ada, but the{resulting programs wouldn't be very good, because they'd fail to take advantage{of the features of Ada.{}q[ 136B131Q131]No, Ada has a reputation for detecting errors earlier than the simpler{languages.  Ada detects errors at compile time that other languages detect only{at run time or not at all.  Examples are calling a subprogram with the wrong{number of parameters, and unintentionally mixing different types in an{expression.  We'll learn more about these things later.{}q[ 136B131Q131]@7WHAT'S A "VALIDATED" ADA COMPILER?{{Although the name "Ada" is no longer a trademark of the Department of Defense,{the Ada Joint Program Office (AJPO) still validates Ada compilers (and cross{compilers).  If a compiler conforms exactly to the standard, and isn't a subset{or superset of Ada, it can be validated after passing an extensive suite of{tests (called the Ada Compiler Validation Capability, or ACVC).{{The ACVC is updated periodically.  Only currently validated compilers may{display an emblem that says, "Validated Ada ... This product conforms to{ANSI/MIL-STD-1815A as determined by the AJPO under its current testing{procedures."{{An unnumbered page in the beginning of the LRM says that "Only compilers which{have been validated ... shall be used in DoD systems."  Also, a 1987 DoD{Directive (3405.2) says that only validated Ada compilers may be used on{mission critical systems.{{As this is written (August, 1994), only Ada 83 compilers can be validated,{because the specifications for Ada 9X have not yet been finalized.{{True or False?  Subsets and supersets of standard Ada may be called "Ada."{}Please press T for true or F for false, or B to go back.[T137F138B131]%You're right!~ Compilers not conforming exactly to the Ada standard may be{called "Ada."  This was true even when "Ada" was a DoD trademark.  A preface to{the LRM says that compilers not conforming to the standard may be called "Ada"{if there's a clear statement that they don't conform.{{Of course, only validated Ada compilers are to be used on DoD systems, and{validated compilers can't be subsets or supersets of standard Ada.{}q[ 139B136Q136]True.  It's a common misconception that subsets and supersets may not be called{"Ada."  However, this was allowed even when "Ada" was a DoD trademark.  A{preface to the LRM says that compilers not conforming to the standard may be{called "Ada" if there's a clear statement that they don't conform.{{It's true that only validated Ada compilers are to be used in DoD systems.{Validated compilers can't be subsets or supersets of standard Ada.{}q[ 139B136Q136]True or False?  The Validation tests are performed to provide reasonable{assurance that a compiler is bug-free.{}Please press T for true or F for false, or B to go back.[F140T141B136]%You're right!~ The Validation tests are performed to make sure that a compiler{conforms to the Ada standard, and isn't a subset or superset.  A compiler isn't{believed to be bug-free just because it earned a Validation Certificate.{}q[ 142B139Q139]False.  That's a common misconception, but validation only determines that a{compiler conforms exactly to the Ada standard, and isn't a subset or superset.{A compiler isn't believed to be bug-free just because it earned a Validation{Certificate.{}q[ 142B139Q139]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Recursion and Assignment 4{{%>  THE FORMAT OF AN ADA PROGRAM~@,Subprograms and Packages{{@#Generic Instantiation and@0Access Types, User Defined Types,{@&Assignment 1@=and Derived Types{{@#Simple Declarations and Simple@+Exceptions, Text_IO, and{@&Attributes@?Assignment 5{{@#Operators, Control Constructs, and@'Generics, Tasking, and Assignment 6{@&Assignment 2{@LMore Records and Types{@#Records, Arrays, and Assignment 3{@LAdvanced Topics{}b[ 143B139]@=OUR FIRST ADA PROGRAM{{Now let's look at a simple Ada program.  This program merely displays "Hello!"{on the screen.{{@8^with Text_IO;`{@8^procedure Hello is`{@8^begin`{@;^Text_IO.Put_Line("Hello!");`{@8^end Hello;`{{Text_IO is a "package" that comes with the Ada language.  We'll learn more{about packages later.  Text_IO contains, among other things, a procedure{Put_Line that takes one parameter of type String and displays it.  In this{case, the String parameter is^"Hello!"`.  Ada doesn't have any special I/O{statements.  I/O is done by calling procedures that Ada provides for us.{{Even though the package Text_IO comes with Ada, our procedure Hello can't "see"{it unless it says^with Text_IO;`.  With that statement, our procedure can call{any procedure or function inside Text_IO.  We call a procedure by giving the{package name (Text_IO), followed by a dot and the name of the procedure within{the package.  Like Pascal and unlike Fortran, the word CALL isn't used in Ada.{}b[ 144B142]@8^with Text_IO;`{@8^procedure Hello is`{@8^begin`{@;^Text_IO.Put_Line("Hello!");`{@8^end Hello;`{{The statement^with Text_IO;~is called a^context clause~because it specifies the{"context" in which procedure Hello is compiled.{{In Ada a^procedure~may be called either from another procedure or as the main{program.  In this example, Hello is the main program; it calls Put_Line.{{Every Ada statement, including the last, ends with a semicolon.  (Technically,{the lines above without semicolons aren't statements.)  In Pascal, semicolons{come^between~statements, but in Ada, a semicolon^ends~a statement.{{In Ada, the^end~statement may optionally give the name of the procedure or{function.  If a name is given, the compiler will check that it agrees with the{name at the beginning.  If it doesn't agree, the compiler will issue a message.{{The statements between^begin~and^end~(this program has only one) are called{executable statements; when they're obeyed they're said to be^executed`.{}b[ 145B143]@?LOCAL DECLARATIONS{{@9with Text_IO;{@9procedure Hello is{@;^I@$: Integer;`{@;^X, Y : Float;`{@9begin{@<Text_IO.Put_Line("Hello!");{@9end Hello;{{Local declarations may appear between^procedure ... is~and^begin`.  This simple{program doesn't need any, but we've added two declarative statements by way of{example.  Executable statements are said to be^executed~when they're obeyed,{but when a declarative statement is obeyed, it's said to be^elaborated`.{Declarative statements are elaborated at run time, not compile time.{{In this example, when the procedure is called (either from another procedure or{as the main program), the declarations are elaborated and variables I, X, and Y{are brought into existence.  Then the executable statement(s) are obeyed.  When{the^end~statement is reached and the procedure returns, I, X, and Y go out of{existence.  These three variables are local to procedure Hello and can't be{referenced outside this procedure.{}b[ 146B144]@9with Text_IO;{@9procedure Hello is{@;^I@$: Integer;`{@;^X, Y : Float;`{@9begin{@<Text_IO.Put_Line("Hello!");{@9end Hello;{{If Hello is called again, I, X, and Y will again be brought into existence, but{their previous values won't necessarily be remembered between calls.  (Of{course, in this simple example, I, X, and Y aren't assigned values anyway.){{Like Pascal and unlike Basic and Fortran, every Ada variable must be declared.{(The index of an Ada^for~loop declares itself, but we'll discuss that later.){Unlike Pascal, Ada programs don't need to say "var".  Ada knows that the{objects declared above are variables.  Constant declarations contain the{reserved word^constant~and may or may not specify a type, like this:{{@5^Pi@%: constant := 3.141592654;`{@5^Two_Pi : constant Float := 2.0 * Pi;`{{Constant declarations that don't specify a type are called^named numbers`.{}b[ 147B145]@5^Pi@%: constant := 3.141592654;`{@5^Two_Pi : constant Float := 2.0 * Pi;`{{Declarations are elaborated in order, top to bottom.  The two declarations{above must appear in the order shown, because the second refers to the first.{{The difference between a named number, like Pi, and a constant declaration that{specifies a type, like Two_Pi, is subtle.  We'll explain the difference in the{section on More Records and Types under "Universal Types."  For now, it doesn't{make any difference whether or not a constant declaration specifies a type.{The compiler can tell, from looking at the constant, whether the type is{Integer or Float.{{Unlike Pascal, Ada allows constant declarations to be intermixed with variable{declarations, so long as no declaration refers to a declaration below it.{}b[ 148B146]@/1@)with Text_IO;{@9procedure Hello is{@/2@,I@$: Integer;{@<X, Y : Float;{@9begin{@/3@,Text_IO.Put_Line("Hello!");{@9end Hello;{{OK, in the program above, where are the^executable statement(s)`?{}Please press 1, 2, or 3, or B to go back.[314911502151B147]@/1@)with Text_IO;{@9procedure Hello is{@/2@,I@$: Integer;{@<X, Y : Float;{@9begin{@.^3@,Text_IO.Put_Line("Hello!");`{@9end Hello;{{%You're right!~ Executable statements are placed between^begin~and^end`.{}q[ 152B148Q148]@/1@)with Text_IO;{@9procedure Hello is{@/2@,I@$: Integer;{@<X, Y : Float;{@9begin{@/3@,Text_IO.Put_Line("Hello!");{@9end Hello;{{No,^with Text_IO;~is a^context clause`.  Executable statements are placed{between^begin~and^end`.{}q[ 152B148Q148]@/1@)with Text_IO;{@9procedure Hello is{@/2@,I@$: Integer;{@<X, Y : Float;{@9begin{@/3@,Text_IO.Put_Line("Hello!");{@9end Hello;{{No,^declarative~statements are placed between^procedure ... is~and^begin`.{%Executable~statements are placed between^begin~and^end`.{}q[ 152B148Q148]@/1@)with Text_IO;{@9procedure Hello is{@/2@,I@$: Integer;{@<X, Y : Float;{@9begin{@/3@,Text_IO.Put_Line("Hello!");{@9end Hello;{{Now, where are the^local declaration(s)`?{}Please press 1, 2, or 3, or B to go back.[215311543155B148]@/1@)with Text_IO;{@9procedure Hello is{@.^2@,I@$: Integer;`{@;^X, Y : Float;`{@9begin{@/3@,Text_IO.Put_Line("Hello!");{@9end Hello;{{%You're right!~ Local declarations are placed between^procedure ... is~and{%begin`.{}q[ 156B152Q152]@/1@)with Text_IO;{@9procedure Hello is{@/2@,I@$: Integer;{@<X, Y : Float;{@9begin{@/3@,Text_IO.Put_Line("Hello!");{@9end Hello;{{No,^with Text_IO;~is a^context clause`.  Local declarations are placed between{%procedure ... is~and^begin`.{}q[ 156B152Q152]@/1@)with Text_IO;{@9procedure Hello is{@/2@,I@$: Integer;{@<X, Y : Float;{@9begin{@/3@,Text_IO.Put_Line("Hello!");{@9end Hello;{{No,^executable~statements are placed between^begin~and^end`. ^Local declarations`{are placed between^procedure ... is~and^begin`.{}q[ 156B152Q152]@;CAPITALIZATION AND SPACING{{@9with Text_IO;{@9procedure Hello is{@<I@$: Integer;{@<X, Y : Float;{@9begin{@<Text_IO.Put_Line("Hello!");{@9end Hello;{{Except in quoted Strings like "Hello!", capitalization isn't important in Ada.{The Ada 9X LRM shows all reserved words in lower case and all identifiers with{initial capitals, so that's the style we're using in our examples.  (The Ada 83{LRM uses all capitals for identifiers.  That style is also commonly used.){{In Ada, unlike Fortran, statements may begin anywhere on the line; columns{aren't significant.  Most people indent the local declarations and the{executable statements two or three spaces, as shown above.  Spaces and tabs may{not appear^within~reserved words and identifiers, but they may freely be used{%between~elements of the program.{}b[ 157B152]@9with Text_IO;{@9procedure Hello is{@<I@$: Integer;{@<X, Y : Float;{@9begin{@<Text_IO.Put_Line("Hello!");{@9end Hello;{{Since a semicolon marks the end of a statement, we can put several statements{on one line, like this:{{@:I : Integer;@#X, Y : Float;{{We can also continue a statement over several lines, breaking anywhere a space{would be permitted, like this:{{@@Text_IO.{@EPut_Line({@E"Hello!");{{Many people follow the capitalization and spacing style of the Ada 9X LRM, so{we'll do that in this course.{}b[ 158B156]@DCOMMENTS{{@*with Text_IO;{@*procedure Hello is{@,^-- This program displays "Hello!" on the screen.`{@-I@$: Integer;^-- These declarations aren't needed; they`{@-X, Y : Float;  ^-- were added only to provide examples.`{@*begin{@-Text_IO.Put_Line("Hello!");{@*end Hello;{{Comments in Ada begin with a double hyphen (double minus sign) and continue{through the end of the line.  No space is permitted inside the double hyphen.{As shown, a comment can be an entire line, or it can follow code on a line.{{Ada programs generally have less need for comments than programs written in{other languages.  The reason is that, as we'll see, the identifiers may be as{long as we like (up to the length of a line) and can have very meaningful{names.  Also, when we learn about named notation, we'll see that calls to{subprograms can be made much more readable in Ada than in other languages.{These features and others tend to make Ada programs self documenting.{}b[ 159B157]@BIDENTIFIERS{{@9with Text_IO;{@9procedure Hello is{@<I@$: Integer;{@<X, Y : Float;{@9begin{@<Text_IO.Put_Line("Hello!");{@9end Hello;{{Here,^reserved words~are in lower case, and all other^identifiers~have initial{captials.  (The Ada reserved words, which may not be used to identify anything{in our programs, are listed on page 7 of your printed course notes, and in{section 2.9 of the LRM.)  Ada identifiers may contain letters, digits, and{underlines, but must start with a letter.  They may not contain spaces or other{characters.  Identifiers may be as long as you like, up to the length of a{line.  (The maximum line length depends on the particular implementation of{Ada.)  All characters are significant, so This_Is_a_Long_Identifier_1 and{This_Is_a_Long_Identifier_2 are distinct.  Since underlines are significant,{A_B is different from AB.  Every underline must be followed by a letter or a{digit.  Thus, you can't have two underlines together, and an identifier can't{end in an underline.{}b[ 160B158]@11.  1553B{{@12.  Begin{{@13.  THIS_IS_A_VERY_LONG_NAME_FOR_AN_IDENTIFIER{{@14.  SYS$QIO{{@15.  Number_Of__Targets{{@16.  Max Speed{{{Only^one~of the above is a legal Ada identifier.  Which is it?{}Please press 1, 2, 3, 4, 5, or 6, or B to go back.[316111622163416451656166B159]@11.  1553B{{@12.  Begin{{@0^3.  THIS_IS_A_VERY_LONG_NAME_FOR_AN_IDENTIFIER`{{@14.  SYS$QIO{{@15.  Number_Of__Targets{{@16.  Max Speed{{{%You're right!~ An Ada identifier may be as long as we like (up to the length of{a line), and upper/lower case isn't important in Ada.{{Number 1 begins with a digit, 2 is a reserved word, 4 has a dollar sign, 5 has{two underlines together, and 6 has a space.{}q[ 167B160Q160]@11.  1553B{{@12.  Begin{{@13.  THIS_IS_A_VERY_LONG_NAME_FOR_AN_IDENTIFIER{{@14.  SYS$QIO{{@15.  Number_Of__Targets{{@16.  Max Speed{{{No, number 1 is illegal because Ada identifiers must begin with a letter.{}q[ 167B160Q160]@11.  1553B{{@12.  Begin{{@13.  THIS_IS_A_VERY_LONG_NAME_FOR_AN_IDENTIFIER{{@14.  SYS$QIO{{@15.  Number_Of__Targets{{@16.  Max Speed{{{No, number 2 is illegal because^begin~is a reserved word.{}q[ 167B160Q160]@11.  1553B{{@12.  Begin{{@13.  THIS_IS_A_VERY_LONG_NAME_FOR_AN_IDENTIFIER{{@14.  SYS$QIO{{@15.  Number_Of__Targets{{@16.  Max Speed{{{No, number 4 is illegal because of the dollar sign.  Ada identifiers may{contain only letters, digits, and underlines.{}q[ 167B160Q160]@11.  1553B{{@12.  Begin{{@13.  THIS_IS_A_VERY_LONG_NAME_FOR_AN_IDENTIFIER{{@14.  SYS$QIO{{@15.  Number_Of__Targets{{@16.  Max Speed{{{No, number 5 is illegal because of the two underlines together.  Every{underline must be followed by a letter or a digit.{}q[ 167B160Q160]@11.  1553B{{@12.  Begin{{@13.  THIS_IS_A_VERY_LONG_NAME_FOR_AN_IDENTIFIER{{@14.  SYS$QIO{{@15.  Number_Of__Targets{{@16.  Max Speed{{{No, number 6 is illegal because of the space.  Ada identifiers may contain only{letters, digits, and underlines.{}q[ 167B160Q160]@DNUMBERS{{In numbers, unlike identifiers, underlines are^not~significant.  Thus^12345~and{%12_345~are equivalent.  Spaces aren't permitted within numbers.  When an{underline appears in a number, it must be surrounded by digits.  Thus, all of{these are illegal:@%123_@%123_.0@%_123@%12__3{{Floating point numbers must have at least one digit before and one digit after{the decimal point.  Unlike Basic and Fortran, Ada forces us to write^1.0`{instead of^1.`, and^0.5~instead of^.5`.  Scientific notation may be used:^1.3E-3`{is the same as^0.0013`.  Non-negative exponents may be used even in integers:{%12E3~means^12_000`.{{Numbers may be specified in any base from 2 to 16, as shown below.  These three{numbers are all equal:{{@*^16#7C03#@)2#0111_1100_0000_0011#@)8#076003#`{{A number with a base may have an exponent.  The number after the^E~is still{written in decimal, and gives the power by which the base is raised.  Thus{%2#110#E5~is 6 times 2**5, or 192.{}b[ 168B160]@7MAKING THE DOT NOTATION AUTOMATIC{{These two programs are equivalent:{{@&with Text_IO;@;with Text_IO;^use Text_IO;`{@&procedure Hello is@6procedure Hello is{@&begin@Cbegin{@(^Text_IO.`Put_Line("Hello!");@-Put_Line("Hello!");{@&end Hello;@>end Hello;{{We've said that the statement^with Text_IO;~makes the package^visible`, so that{our program can call the procedures and functions in it.  To call a procedure,{we write the name of the package, a dot, and the name of the procedure.{{The statement^use Text_IO;~tells the compiler to supply the name of the package{and the dot for us.  That's why the two programs above are equivalent.{{Remember, in Ada^with~provides visibility;^use~asks the compiler to supply the{package name and the dot.{{The Ada meanings of the words^with~and^use~are more or less reversed from their{meanings in Pascal.  Also, in Ada one can't^use~records, only packages.{}b[ 169B167]@&with Text_IO;@;with Text_IO;^use Text_IO;`{@&procedure Hello is@6procedure Hello is{@&begin@Cbegin{@(^Text_IO.`Put_Line("Hello!");@-Put_Line("Hello!");{@&end Hello;@>end Hello;{{A program can^with~and^use~several packages.  For example, there's a package{that comes with Ada called Calendar.  Suppose we've also compiled two packages{of our own, called My_Pkg_1 and My_Pkg_2.  Then our program might say{{@1^with Text_IO, Calendar, My_Pkg_1, My_Pkg_2;`{@1^use  Text_IO, Calendar, My_Pkg_1, My_Pkg_2;`{{In this case, when the compiler sees the call to Put_Line, it will search all{four packages that we've^use`d for a procedure Put_Line that takes one String{parameter (or "argument").  If it finds no procedure Put_Line, the compiler{will display an error message, like "Put_Line is not declared" or "Undeclared{identifier Put_Line."{{You may ask, what if there are several procedures Put_Line among the four{packages?  Will the compiler stop searching when it finds the first Put_Line?{No.{}b[ 170B168]@1^with Text_IO, Calendar, My_Pkg_1, My_Pkg_2;`{@1^use  Text_IO, Calendar, My_Pkg_1, My_Pkg_2;`{{If the compiler finds several Put_Line's, the name Put_Line is said to be{%overloaded`.  In that case the compiler will use the^number~and^types~of{parameters (arguments) to try to select the right Put_Line.  For example, if{Text_IO contains a Put_Line that takes one String parameter, and My_Pkg_1{contains a Put_Line that takes one Integer parameter, the compiler will write a{call to Text_IO.Put_Line and not My_Pkg_1.Put_Line, because the calling{statement supplies one String parameter.{{If there's more than one Put_Line that takes exactly one String parameter, then{the call is ambiguous and the compiler can't resolve the overloading.  The{error message will be something like "Ambiguity detected during overload{resolution" or "Ambiguous expression."  In that case, we'd have to specify{%Text_IO.`Put_Line even though we said^use Text_IO;`.{{Finally, if there are procedures Put_Line, but none of them has the right{number and types of parameters, the error message will be something like{"Inconsistency detected during overloading resolution" or "Unresolvable{expression."{}b[ 171B169]In summary, the compiler will search all the packages that we've^use`d for a{procedure with the correct number and types of parameters.  If it finds exactly{one, everything's fine.  If it finds no procedure with the correct name, the{error message will be something like "Undeclared identifier."  If it finds more{than one procedure with the correct number and types of parameters, the message{is "Ambiguity detected during overload resolution" or "Ambiguous expression."{Finally, if it finds one or more procedures with the correct name, but none of{them has the right number and types of parameters, the message will be{something like "Inconsistency detected during overload resolution" or{"Unresolvable expression."{{Overloading may seem like an unnecessary complication at this point, but you'll{see later how very useful it can be.  Overloading is especially useful with{the infix operators when we create our own types.  All of this will be covered{later.{}b[ 172B170]Which^one~of the following would most likely be the cause of the message{"Inconsistency detected during overload resolution"?{{{@$1.  You tried to^use~a package that you didn't^with`.{{@$2.  You misspelled the name of a package in a call using dot notation.{{@$3.  You misspelled the name of a procedure or function in a call.{{@$4.  You called a procedure or function with the wrong number or types of{@(parameters.{}Please press 1, 2, 3, or 4, or B to go back.[4173117421753175B171]@$1.  You tried to use a package that you didn't with.{{@$2.  You misspelled the name of a package in a call using dot notation.{{@$3.  You misspelled the name of a procedure or function in a call.{{@#^4.  You called a procedure or function with the wrong number or types of`{@'^parameters.`{{{%You're right!~ The message "Inconsistency detected during overload resolution"{usually means that you called a procedure or a function with the wrong number{or types of parameters.{}q[ 176B172Q172]@$1.  You tried to^use~a package that you didn't^with`.{{@$2.  You misspelled the name of a package in a call using dot notation.{{@$3.  You misspelled the name of a procedure or function in a call.{{@$4.  You called a procedure or function with the wrong number or types of{@(parameters.{{{No, for number 1 the message would be something like "This package is not named{in a prior^with~clause," or "%use~clause was not expected here."{}q[ 176B172Q172]@$1.  You tried to^use~a package that you didn't^with`.{{@$2.  You misspelled the name of a package in a call using dot notation.{{@$3.  You misspelled the name of a procedure or function in a call.{{@$4.  You called a procedure or function with the wrong number or types of{@(parameters.{{{No, if you misspell the name of a package, procedure, or function, the most{probable error message would be "Undeclared identifier."{}q[ 176B172Q172]Text_IO contains both a procedure^Put~and a procedure^Put_Line~(among other{things). ^Put_Line~displays its String parameter followed by a Carriage Return{and a Line Feed, while^Put~displays its String parameter without the CR-LF.{Text_IO also contains a procedure^New_Line~which produces only CR-LF.  For{example, the following program will display^Hi there,~leave a blank line, and{display^everybody!`:{{@:with Text_IO; use Text_IO;{@:procedure Hi_There is{@:begin{@<^Put`("Hi");{@<^Put_Line`(" there,");{@<^New_Line;`{@<^Put_Line`("everybody!");{@:end Hi_There;{}b[ 177B172]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Recursion and Assignment 4{{@#The Format of an Ada Program@-Subprograms and Packages{{%>  GENERIC INSTANTIATION AND~@/Access Types, User Defined Types,{@%^ASSIGNMENT 1~@<and Derived Types{{@#Simple Declarations and Simple@+Exceptions, Text_IO, and{@&Attributes@?Assignment 5{{@#Operators, Control Constructs, and@'Generics, Tasking, and Assignment 6{@&Assignment 2{@LMore Records and Types{@#Records, Arrays, and Assignment 3{@LAdvanced Topics{}b[ 178B176]@>DISPLAYING INTEGERS{{with Text_IO; use Text_IO;@;with Text_IO; use Text_IO;{procedure Hello is@,^THIS~@'^THIS~@$procedure Add is{begin@6^<= IS~@+^IS =>~ begin{@#Put_Line(%"Hello!"`);@(^RIGHT~@%^WRONG~@'Put_Line(%2 + 2`);{end Hello;@Kend Add;{{Now let's write a program called Add that computes 2 + 2 and displays the{result.  You may think that we could take the Hello program and substitute{%2 + 2~for^"Hello!"`, but that won't work.  (We never said Ada is easy!)  Why{won't it work?  Because Text_IO doesn't have a procedure Put_Line that takes an{Integer parameter.  One correct program is this:{{@(with Text_IO; use Text_IO;{@(procedure Add is{@*^package My_Int_IO is new Integer_IO(Integer); use My_Int_IO;`{@(begin{@*^Put(2 + 2);`{@*^New_Line;`{@(end Add;{}b[ 179B177]@(with Text_IO; use Text_IO;{@(procedure Add is{@*^package My_Int_IO is new Integer_IO(Integer); use My_Int_IO;`{@(begin{@+Put(2 + 2);{@+New_Line;{@(end Add;{{__________ Text_IO __________  The package Text_IO contains procedures for type{| Put_Line for type String  |  String.  This package is ready-to-use.  However,{| Put@&for type String  |  inside Text_IO is another package, Integer_IO,{| Get_Line for type String  |  that's^not~ready-to-use.  It's called a^generic`{| Get@&for type String  |  package because it has an empty^box~(%<>`) in{| New_Line@2|  place of the type.  We can make a new, ready-to-{| ...@7|  -use package from Integer_IO by giving the type:{|@;|  package My_Int_IO is new Integer_IO(%Integer`); we{|  ______ Integer_IO ______ |  could have used any name in place of My_Int_IO.{|  | Put for type <>@&| |  Note that we've declared our new package locally{|  | Get for type <>@&| |  inside the procedure Add.  My_Int_IO now has the{|  | ...@2| |  same procedures and functions as Integer_IO, but{|  |______________________| |  with the empty box filled in with the type{|___________________________|  Integer, like this:{}b[ 180B178]@@with Text_IO; use Text_IO;{__________ Text_IO __________@#procedure Add is{| Put_Line for type String  |@%^package My_Int_IO is new Integer_IO(`{| Put@&for type String  |@*^Integer); use My_Int_IO;`{| Get_Line for type String  |@#begin{| Get@&for type String  |@%^Put(2 + 2);`{| New_Line@2|@%^New_Line;`{| ...@7|@#end Add;{|@;|{|  ______ Integer_IO ______ |@#^______ My_Int_IO _______`{|  | Put for type <>@&| |@#^| Put for type Integer |`{|  | Get for type <>@&| |@#^| Get for type Integer |`{|  | ...@2| |@#^| ...@2|`{|  |______________________| |@#^|______________________|`{|___________________________|{{Since Integer_IO (and therefore My_Int_IO) doesn't have a Put_Line, we call{My_Int_IO.Put and then Text_IO.New_Line.  Note that our program says{%use My_Int_IO;~after declaring My_Int_IO.  When the compiler sees the call{%Put(2 + 2);~it writes code to call My_Int_IO.Put rather than Text_IO.Put,{because My_Int_IO.Put takes a parameter of type Integer.  The compiler then{finds New_Line in Text_IO and writes a call to Text_IO.New_Line.{}b[ 181B179]True or False?  In our example, a program could call^Integer_IO.Put`.{}Please press T for true or F for false, or B to go back.[F182T183B180]%You're right!~ Since Integer_IO is generic, a program can't call its procedures{and functions.  The program must specify the type and create an^instance~of{Integer_IO, such as My_Int_IO.  It can then call Put in My_Int_IO.  Note also{that we can't^use~a generic package like Integer_IO, but only an instance of it{like My_Int_IO.{}q[ 184B181Q181]False.  Since Integer_IO is generic, a program can't call its procedures and{functions.  The program must specify the type and create an^instance~of{Integer_IO, such as My_Int_IO.  It can then call Put in My_Int_IO.  Note also{that we can't^use~a generic package like Integer_IO, but only an instance of it{like My_Int_IO.{}q[ 184B181Q181]@=GENERIC INSTANTIATION{{@0^package My_Int_IO is new Integer_IO(Integer);`{{@.______ Integer_IO ______@#^______ My_Int_IO _______`{@.| Put for type <>@&|@#^| Put for type Integer |`{@.| Get for type <>@&|@#^| Get for type Integer |`{@.| ...@2|@#^| ...@2|`{@.|______________________|@#^|______________________|`{{This process of creating an^instance~of the generic package Integer_IO for the{type Integer is called^generic instantiation`.  Later in this course we'll{learn to write our own generic packages, procedures, and functions.  However,{we wanted to learn, early in the course, how to instantiate an already written{generic package in order to display integers.{{But why does Ada make Text_IO ready-to-use for Strings, while Integer_IO is{generic, and has to be instantiated for Integers?  Because programs normally{use only one type String, but can have several integer types.  Right now, we{know of only one integer type, the standard Integer.  Later we'll learn about{user-defined types and derived types, and we'll see how there can be many{integer types.  Integer_IO can be instantiated for each of these types.{}b[ 185B181]Since Integer_IO is often instantiated for the standard Integer type, some{implementations of Ada provide an already-instantiated package for the type{Integer, equivalent to our package My_Int_IO.  However, an implementation of{Ada need not supply such a package to meet the Ada standard.  Our program did{its own instantiation of Integer_IO so that it would run on any Ada that meets{the standard.{{There's another generic package within Text_IO called Float_IO.  Input and{output of floating point numbers is done by instantiating Float_IO for the type{Float.  As with integers, we'll later learn how there can be several floating{point types besides the standard Float.{{Later in this course, when we cover attributes, we'll learn another way to{display Integers by using the^'Image~attribute.{{We're now ready for our first Outside Assignment!  Let's compile and run our{two sample programs, Hello and Add.{}b[ 186B184]@*OUTSIDE ASSIGNMENT 1 - PREPARING TO RUN ADA ON YOUR COMPUTER{{Since these screens disappear, you'll probably want to refer to your printed{course notes when doing the Outside Assignments.  The first assignment appears{on page 8.  In this assignment, we'll compile, link, and run our first two{programs, Hello and Add.{{First compile HELLO.ADA, then link, and then execute the program.  The exact{steps will depend on the Ada compiler you're using.  You'll probably have to{refer to the documentation that came with your compiler.  Note that some{implementations of Ada use the term "binding" instead of "linking."  When you{run the program, it should display^Hello!~on your screen.{{Then compile ADD.ADA, link, and run the program.{{When we compile, we specify the name of the source file being compiled.  Many,{but not all, implementations of Ada assume the extension to be .ADA if it's not{specified.  When we link, we specify the name of the main program, which in our{examples agrees with the name of the source file.  The linking step produces a{file which we can execute.{}b[ 187B185]Before we can compile an Ada program, we must create our own Ada library.  Some{implementations of Ada come with a library already created for us; others{require us to type a command to create a library.  When we compile HELLO.ADA{and ADD.ADA, the procedures HELLO and ADD are added to our library.  We'll{discuss the Ada library in more detail later.{{If you haven't done so already, please type X to exit^ADA-TUTR~temporarily,{read page 8 of your printed course notes, and try the first Outside Assignment.{{When you finish Outside Assignment 1, we'll go on to discuss the Ada library{and separate compilation of program units.{}Please type X to exit, a space to go on, or B to go back.[ 188B186]@-^Congratulations on Completing Outside Assignment 1!`{{We know this first assignment wasn't very interesting, because the programs{HELLO.ADA and ADD.ADA were supplied for you.  But we had to be sure we can{compile, link, and execute Ada programs, so we can do the remaining{assignments.{{The rest of the Outside Assignments should be more challenging!{{Let's go on to discuss the Ada library and separate compilation of program{units.{}b[ 189B187]@@THE ADA LIBRARY{{What's the difference between an Ada library, and, say, a Fortran library?{Compilers for languages other than Ada simply take source code and produce{object code.  Compiling a Fortran program doesn't change the Fortran library.{Ada compilers, however, take source code and a library and produce object code{and an updated library. ^The Ada library remembers what we've compiled.~ Other{languages have libraries of functions, etc., but they're fixed and don't{remember what we've compiled.{@@________________{@?|@0|{@-Source Code@'|  Fortran,@&|@&Object Code{@'----------------------->|  Pascal, etc.  |----------------------->{@?|  Compiler@&|{@?|________________|{{@@________________{@-Source Code@'|@0|@&Object Code{@'----------------------->|  Ada@+|----------------------->{@-Ada Library@'|  Compiler@&|  Updated Ada Library{@'----------------------->|@0|----------------------->{@?|________________|{}b[ 190B188]Ada gives us the advantage that compilation is^separate but dependent`.  Some{languages, such as Fortran, offer^separate and independent~compilation.  A{Fortran main program and a subroutine can be compiled independently, perhaps a{month apart.  When the subroutine is compiled, Fortran knows nothing about the{main program, and vice versa.  An advantage of^separate~compilation is that we{can develop our program one piece at a time and compile each piece as it's{developed.  However, the^independent~compilation is a disadvantage.  The{compiler can't check that the number and types of parameters in the call agree{with the number and types of parameters in the subroutine.  A Fortran main{program might say^CALL SUB(I, J, K)`, while the subroutine might say{%SUBROUTINE SUB(I, J)`.  Both of these will compile correctly.  When the program{is run, however, the results are unpredictable.  The program might simply give{wrong answers with no warning.{{Other languages, such as early Pascal and many versions of Basic, don't have{separate compilation at all.  The compiler could check the number and types of{parameters in a call, because the entire program must be compiled at one time.{But the advantages of separate compilation are lost.  We can't develop the{program one piece at a time, compiling each piece as it's developed.  And if we{make the slightest change in one part of the program, the whole program has to{be recompiled.{}b[ 191B189]Ada gives us the advantages of both systems, because compilation is^separate{but dependent`.  We can compile a subprogram today and the calling program next{month.  (We could also put both into one file and compile them together.)  Each{compilation unit updates the library when it's successfully compiled.  Thus,{when a call to a subprogram is encountered, the compiler will check the number{and types of parameters against the subprogram already in the library.{{We could also write the calling program^before~the subprogram, because Ada lets{us compile the subprogram^specification~separately from its^body`.  (We'll learn{more about that later.)  The specification contains the name of the subprogram,{and the names, number, and types of any parameters.  The specification also{tells which parameters are inputs, which are outputs, and which are both inputs{and outputs.  That's all the information the compiler needs to compile calls to{the subprogram; the body can be supplied later.  When the subprogram body is{compiled, the compiler will make sure it's consistent with the specification.{{Ada comes with several packages, such as Text_IO.  These are already compiled{and placed into the library.  That's why our programs can say^with Text_IO;~and{call its procedures and functions.{{Ada libraries are a complication compared to other languages, but they offer{great advantages in program development.{}b[ 192B190]True or False?  A procedure specification must be compiled before calls to the{procedure can be compiled.{}Please press T for true or F for false, or B to go back.[T193F194B191]%You're right!~ The specification contains all the information the compiler{needs to compile calls to the procedure.{}q[ 195B192Q192]True.  The compiler needs the information in the specification to compile calls{to the procedure.  However, the procedure^body~can be compiled later.{}q[ 195B192Q192]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Recursion and Assignment 4{{@#The Format of an Ada Program@-Subprograms and Packages{{@#Generic Instantiation and@0Access Types, User Defined Types,{@&Assignment 1@=and Derived Types{{%>  SIMPLE DECLARATIONS AND SIMPLE~@*Exceptions, Text_IO, and{@%^ATTRIBUTES~@>Assignment 5{{@#Operators, Control Constructs, and@'Generics, Tasking, and Assignment 6{@&Assignment 2{@LMore Records and Types{@#Records, Arrays, and Assignment 3{@LAdvanced Topics{}b[ 196B192]@=VARIABLES AND CONSTANTS{{@&procedure Declarations_Demo is{@(^I, J, K : Integer;`{@(^L, M@$: Integer := 30;`{@)F, G@$: Float;{@)Factor  : constant := 1000;{@&begin{@)J := L + 10;@*-- Simple assignment statements.{@)F := 0.0;{@)G := F + L;@+-- ILLEGAL.  Can't accidentally mix types.{@)G := F + Float(L);@$-- Legal.  May deliberately convert types.{@)K := Integer(F) + L;  -- Legal.{@)Factor := 1000;@'-- ILLEGAL.  Factor is a constant.{@&end Declarations_Demo;{{This program doesn't do anything except demonstrate Ada declarations.  The{statement^I, J, K : Integer;~brings three integer variables into existence.{The next statement creates two more integer variables and initializes both of{them to 30.  Every time this procedure is called, L and M are brought into{existence and initialized to 30.  This is different from a Fortran DATA{statement, which initializes only once at compile time.{}b[ 197B195]@&procedure Declarations_Demo is{@)I, J, K : Integer;{@)L, M@$: Integer := 30;{@(^F, G@$: Float;`{@(^Factor  : constant := 1000;`{@&begin{@(^J := L + 10;@*-- Simple assignment statements.`{@(^F := 0.0;`{@(^G := F + L;@+-- ILLEGAL.  Can't accidentally mix types.`{@)G := F + Float(L);@$-- Legal.  May deliberately convert types.{@)K := Integer(F) + L;  -- Legal.{@)Factor := 1000;@'-- ILLEGAL.  Factor is a constant.{@&end Declarations_Demo;{{The statement^F, G@$: Float;~creates two variables of type Float.  The next{statement names a constant.  Writing^Factor~is thereafter equivalent to writing{%1000`.  Unlike variables, constants^must~be initialized.{{The first two executable statements are simple assignment statements.  The{symbol^:=~is read "becomes" or "gets."  It may not contain a space.  In the{third executable statement, the compiler will reject the expression^F + L`{because Ada doesn't let us accidentally mix a Float with an Integer.{}b[ 198B196]@&procedure Declarations_Demo is{@)I, J, K : Integer;{@)L, M@$: Integer := 30;{@)F, G@$: Float;{@)Factor  : constant := 1000;{@&begin{@)J := L + 10;@*-- Simple assignment statements.{@)F := 0.0;{@)G := F + L;@+-- ILLEGAL.  Can't accidentally mix types.{@(^G := F + Float(L);@$-- Legal.  May deliberately convert types.`{@(^K := Integer(F) + L;  -- Legal.`{@(^Factor := 1000;@'-- ILLEGAL.  Factor is a constant.`{@&end Declarations_Demo;{{However, Ada lets us^deliberately~mix types.  The statement^G := F + Float(L);`{is legal because it converts L from Integer to Float, adds it to F which is of{type Float, and stores the result in G, also of type Float.  Likewise, the next{statement is legal because it converts F to Integer, adds the integer L, and{stores the result in the integer K.  But note that when a Float is converted to{Integer, it's rounded, not truncated.  (Later we'll present two functions that{truncate integers.)  The last executable statement is illegal because a{constant can't appear on the left side of an assignment statement.{}b[ 199B197]@'^with Text_IO; use Text_IO;`{@'^procedure Try_Me is`{@*^package My_Int_IO is new Integer_IO(Integer); use My_Int_IO;`{@*^N : Integer := 1;`{@'^begin`{@*^Put(N);`{@*^New_Line;`{@*^N := 2;`{@'^end Try_Me;`{{What number will be displayed the^second~time procedure Try_Me is called?{{@81.  The program will display 1.{{@82.  The program will display 2.{}Please press 1 or 2, or B to go back.[12002201B198]@'^with Text_IO; use Text_IO;`{@'^procedure Try_Me is`{@*^package My_Int_IO is new Integer_IO(Integer); use My_Int_IO;`{@*^N : Integer := 1;`{@'^begin`{@*^Put(N);`{@*^New_Line;`{@*^N := 2;`{@'^end Try_Me;`{{%You're right!~ N is brought into existence and initialized to 1 each time the{procedure is called, so 1 will be displayed.{}q[ 202B199Q199]@(with Text_IO; use Text_IO;{@(procedure Try_Me is{@+package My_Int_IO is new Integer_IO(Integer); use My_Int_IO;{@+N : Integer := 1;{@(begin{@+Put(N);{@+New_Line;{@+N := 2;{@(end Try_Me;{{No, N is declared locally within Try_Me.  So N is brought into existence and{initialized to 1^each~time the procedure is called, and the procedure will{display 1 each time.  Also remember that N goes out of existence when Try_Me{returns, so the statement N := 2; has no effect.{}q[ 202B199Q199]@?ENUMERATION TYPES{{In Ada we can declare^enumeration types`, where we enumerate every possible{value for a type.  For example, if we declare{{  ^type Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);`{  ^Rc : Rainbow_Color;`{{then Rc can have any of 7 values.  In the executable region we might write{%Rc := Red;~and we could also test:^if Rc = Red then~...^end if;`.  The{enumerated values, enclosed in parentheses, must follow the rules for Ada{identifiers, or they can be single^characters~enclosed in^'~marks (called "tic"{marks), thus:{{@1^type Even_Digit is ('0', '2', '4', '6', '8');`{{It's illegal to write^type Processor is (80386, Z80, 1750A);~because two of the{values aren't legal Ada identifiers.  However, it's OK to mix characters and{identifiers in the same declaration, thus:{{@4^type Mixed is (Big, Small, 'X', '9');`{}b[ 203B199]  ^type Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);`{  ^type Traffic_Light_Color is (Red, Amber, Green);`{  ^Rc : Rainbow_Color;`{  ^Tc : Traffic_Light_Color;`{{With the above declarations, Rc could have any of 7 values, and Tc could have{any of 3 values.  The compiler will have no trouble compiling{{@B^Rc := Red;`{@B^Tc := Red;`{{because it knows that in^Rc := Red;~Red must be the Rainbow_Color if it's{stored into Rc, and in^Tc := Red;~Red must be the Traffic_Light_Color if it's{stored into Tc.  The compiler knows that the types across^:=~must always match.{Naturally, it's illegal to write^Rc := 2;~because of the mixed types.{{Also, if we have a procedure Display that takes one parameter of type{Rainbow_Color, the compiler could handle^Display(Red);~because it knows that{Red must be the Rainbow_Color to fit the procedure.{}b[ 204B202]  ^type Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);`{  ^type Traffic_Light_Color is (Red, Amber, Green);`{{However, if we had a procedure Display that takes one Rainbow_Color and another{procedure Display that takes one Traffic_Light_Color, then the statement{%Display(Red);~would be ambiguous; the compiler couldn't possibly know which{Display to call.  In that case, we could specify the type by writing{%Rainbow_Color'(Red)`.  This is called^qualifying~the name Red; note the^'~with{the parentheses.  The call would be written^Display(Rainbow_Color'(Red));`.  The{statements^Display(Violet);~and^Display(Amber);~aren't ambiguous; the compiler{will figure out which Display to call in these cases.{{Declaring an enumeration type not only defines equality for objects of that{type, but also an order for the values.  Thus we can check for <, >, <=, etc.{For example, if we declare^A, B: Rainbow_Color;~and later write, in the{executable region,^A := Yellow;~and^B := Blue;~then the test^if A < B then~...{%end if;~will turn out to be True. ^Yellow~is considered less than^Blue`.{{Input and output of enumeration types can be done by instantiating the generic{package Text_IO.Enumeration_IO.  For example:{%with Text_IO; use Text_IO;~...{%package My_Rainbow_IO is new Enumeration_IO(Rainbow_Color); use My_Rainbow_IO;`{}b[ 205B203]Here are two enumeration types built into Ada 83:{{@%^type Boolean is (False, True);`{{@%^type Character is (~(nul)%,~(soh)%,~(stx)%,~...^, ' ', '!', '"',~...^,`{@9^'0', '1', '2',~...^, 'A', 'B', 'C',~...^,`{@9^'a', 'b', 'c',~...^,~(del)^);`{{Since the above two declarations are built into the Ada language, they{shouldn't be repeated in your programs.  Note that type Boolean is just an{enumeration type.  The relational operators (^=`,^>`,^<=`, etc. ) all return{results of type Boolean.{{The definition of type Character can't be completely written out, because there{are 33 unprintable ASCII characters.  However, the enumeration type Character{contains all 128 values, in ASCII character order.  On this screen, we've{denoted the unprintable characters with names in parentheses, and we've also{used "..." for brevity.  Even if Ada is run on an EBCDIC machine, it's{guaranteed that type Character contains the 128 ASCII characters in ASCII{character order.  (In Ada 9X, type Character contains all 256 8-bit values, and{a type Wide_Character is also defined, containing all 65,536 16-bit values.){}b[ 206B204]@.1.  type Count is ("1", "2", "3", "Ab", "Cd", "Ef");{{@.2.  type Count is ('1', '2', '3', 'Ab', 'Cd', 'Ef');{{@.3.  type Count is (1, 2, 3, Ab, Cd, Ef);{{@.4.  type Count is ('1', '2', '3', Ab, Cd, Ef);{{{Which^one~of the above type declarations is legal?{}Please press 1, 2, 3, or 4, or B to go back.[4207120822093210B205]@.1.  type Count is ("1", "2", "3", "Ab", "Cd", "Ef");{{@.2.  type Count is ('1', '2', '3', 'Ab', 'Cd', 'Ef');{{@.3.  type Count is (1, 2, 3, Ab, Cd, Ef);{{@-^4.  type Count is ('1', '2', '3', Ab, Cd, Ef);`{{{%You're right!~ Enumeration types can contain single characters between^'~marks,{and Ada identifiers.  Number 1 is illegal because it contains Strings, number 2{is illegal because^'~marks may enclose only single characters, and number 3 is{illegal because an Ada identifier can't begin with a digit.{}q[ 211B206Q206]@.1.  type Count is ("1", "2", "3", "Ab", "Cd", "Ef");{{@.2.  type Count is ('1', '2', '3', 'Ab', 'Cd', 'Ef');{{@.3.  type Count is (1, 2, 3, Ab, Cd, Ef);{{@.4.  type Count is ('1', '2', '3', Ab, Cd, Ef);{{{No, number 1 is illegal because an enumeration type can't contain Strings, only{single characters between^'~marks, and Ada identifiers.{}q[ 211B206Q206]@.1.  type Count is ("1", "2", "3", "Ab", "Cd", "Ef");{{@.2.  type Count is ('1', '2', '3', 'Ab', 'Cd', 'Ef');{{@.3.  type Count is (1, 2, 3, Ab, Cd, Ef);{{@.4.  type Count is ('1', '2', '3', Ab, Cd, Ef);{{{No, number 2 is illegal because only single characters may appear between^'`{marks.  Enumeration types contain single characters between^'~marks, and Ada{identifiers.{}q[ 211B206Q206]@.1.  type Count is ("1", "2", "3", "Ab", "Cd", "Ef");{{@.2.  type Count is ('1', '2', '3', 'Ab', 'Cd', 'Ef');{{@.3.  type Count is (1, 2, 3, Ab, Cd, Ef);{{@.4.  type Count is ('1', '2', '3', Ab, Cd, Ef);{{{No, number 3 is illegal because an Ada identifier can't begin with a digit.{Enumeration types can contain only single characters between^'~marks, and Ada{identifiers.{}q[ 211B206Q206]@DSUBTYPES{{A subtype does^not~define a new type, but it imposes a range constraint on{objects of that subtype.  For example,{{%subtype Day_Subtype is Integer range 1 .. 31;{D : Day_Subtype; -- D can have only Integer values from 1 to 31.`{{type Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);{%subtype Bright_Color is Rainbow_Color Range Orange .. Green;{B : Bright_Color; -- B can have only Rainbow_Color values from Orange to Green.`{{%subtype Probability is Float range 0.0 .. 1.0;{P : Probability; -- P can have only Float values from 0.0 to 1.0.`{{Every time the program stores a value into D, B, or P, a check is made to see{if the value is in range.  If it isn't, the message Constraint_Error is{displayed.  Constraint Errors are usually detected at run time.{{Since subtypes don't define new types, the^type~of D is Integer, the type of B{is Rainbow_Color, and that of P is Float.  Thus, if we write^I : Integer;~we{may write^D := D + I;~etc., because D and I have the same type.{}b[ 212B206]We don't have to supply a name for the subtype explicitly.  If we declare{{@:^D : Integer range 1 .. 31;`{{the compiler creates its own name for the subtype internally; we never see it.{This is called an^anonymous~subtype.  The name the compiler creates will be one{that we can't accidentally create ourselves.  Perhaps it will contain a control{character or punctuation mark that Ada doesn't allow us to put into an{identifier.  The above declaration is equivalent to{{@0^subtype~(something)^is Integer range 1 .. 31;`{@0^D :~(something)%;`{{where (something) represents the anonymous subtype that we can't see or write.{}b[ 213B211]@?SIMPLE ATTRIBUTES{{An^attribute~consists of an apostrophe (called a "tic" mark for short), and the{name of the attribute.  Attributes often follow type names.  They're something{like functions, except that they usually involve a type.  For example:{{@#type Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);{@#type Traffic_Light_Color is (Red, Amber, Green);{  ^Rainbow_Color'Succ(Green)~@&is^Blue`{  ^Traffic_Light_Color'Pred(Green)~is^Amber`{{The attributes^Succ~and^Pred~stand for successor and predecessor, respectively.{In Rainbow_Colors, the successor of^Green~is^Blue`, and in Traffic_Light_Colors,{the predecessor of^Green~is^Amber`.  Thus we could write^R : Rainbow_Color;~and{then^R := Rainbow_Color'Succ(Green);`.  You'll get a Constraint_Error if you{try to take the successor of the last value or the predecessor of the first;{for example, taking Rainbow_Color'Pred(Red) will cause an error.{{Succ and Pred work with any^discrete type`.  That means any integer type or{enumeration type.  These two attributes aren't particularly useful with integer{types, because we can simply add or subtract 1 instead.  So they're usually{used with enumeration types.{}b[ 214B212]@#type Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);{@#type Traffic_Light_Color is (Red, Amber, Green);{{The attribute^Pos~converts from a discrete type to an integer, and^Val~converts{from an integer to a discrete type.  Again, the type is usually an enumeration{type, because there's little point converting from integer to integer.{{For example,^Rainbow_Color'Pos(Orange)~is^1`.  (The positions are numbered from{zero.) ^Rainbow_Color'Pos(Red)~is^0~and^Rainbow_Color'Pos(Violet)~is^6`.{%Traffic_Light_Color'Pos(Green)~is^2`, but^Rainbow_Color'Pos(Green)~is^3`.{%Character'Pos('A')~is^65`, because the ASCII value of 'A' is 65, and the{Ada 83 type Character contains all 128 characters in ASCII order.{%Character'Pos('0')~is^48`, because the ASCII value of the character '0' is 48.{(Note that in Ada 9X, Character'Pos can be as high as 255, because the Ada 9X{type Character contains 256 values, from position 0 through position 255.){{%Val~converts the other way, so^Rainbow_Color'Val(0)~is^Red`, and{%Rainbow_Color'Val(6)~is^Violet`.  Taking the Rainbow_Color'Val of a parameter{outside the range 0 .. 6 will raise a Constraint_Error. ^Character'Val(65)~is{%'A'`, and^Character'Val(7)~is the "bell" character (control-G).  Since Boolean{is an enumeration type,^Boolean'Val(0)~is^False~and^Boolean'Val(1)~is^True`.{}b[ 215B213]@%type Month_Type is (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);{{@:What is Month_Type'Pos(Feb)?{{{@:1.  Month_Type'Pos(Feb) is 1.{{@:2.  Month_Type'Pos(Feb) is 2.{}Please press 1 or 2, or B to go back.[12162217B214]@%type Month_Type is (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);{{%You're right!~ The positions are numbered from zero, so Feb is in position 1,{and Month_Type'Pos(Feb) is 1.{}q[ 218B215Q215]@%type Month_Type is (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);{{No, the positions are numbered from zero, so Feb is in position 1, and{Month_Type'Pos(Feb) is 1.{}q[ 218B215Q215]While^Pos~and^Val~convert to and from integers, the attributes^Image~and^Value`{convert to and from Strings.  They work with any discrete types, and are useful{with integer types as well as enumeration types.  For example,{{@#type Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);{@#type Traffic_Light_Color is (Red, Amber, Green);{{  ^Rainbow_Color'Value("RED")~@&is^Red`{  ^Rainbow_Color'Value("yellow")~@#is^Yellow`{  ^Traffic_Light_Color'IMAGE(Amber)~is^"AMBER"`{{  ^Integer'Value("123")~is^ 123`{  ^Integer'Image(123)~  is^" 123"`{  ^Integer'Image(-123)~ is^"-123"`{{If I is an Integer, we can write^Put(Integer'Image(I));~without having to{instantiate Integer_IO.  However, this won't work for type Float, only for{discrete types. ^Value~will raise a Constraint_Error if the String can't be{converted to the discrete type.  For example, taking^Integer'Value("12X3")~or{%Rainbow_Color'Value("CHARTREUSE")~will normally display Constraint_Error on the{screen and stop the program.{}b[ 219B215]For any discrete type, the attributes^First~and^Last~are also available.{{@#type Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);{@#type Traffic_Light_Color is (Red, Amber, Green);{  ^Rainbow_Color'First~@%is^Red`{  ^Traffic_Light_Color'Last~is^Green`{{A program can use these attributes with Integer to determine the size of{integers on the host computer.  For example, if your PC Ada has 16-bit 2's{complement integers, while a mainframe Ada uses 32-bit 2's complement, then{{@#^Integer'First~is^-32_768~on your PC and^-2_147_483_648~on the mainframe.{@#^Integer'Last~ is ^32_767~on your PC and^ 2_147_483_647~on the mainframe.{{Most attributes may also be used with subtypes:{@1subtype Day_Subtype is Integer range 1 .. 31;{@0^Day_Subtype'First~is^1`{@0^Day_Subtype'Last~ is^31`{{There are two subtype definitions involving^Last~built into the Ada language:{@-^subtype Positive is Integer range 1 .. Integer'Last;`{@-^subtype Natural  is Integer range 0 .. Integer'Last;`{}b[ 220B218]More attributes are discussed in the Advanced Topics section.  In summary,{%discrete type~means any integer or enumeration type.  (The only integer type{we've learned about so far is the standard Integer.){{@&^Pos~converts from a discrete type to an integer.{@&^Val~converts from an integer to a discrete type.{@&^Image~converts from a discrete type to String.{@&^Value~converts from String to a discrete type.{@&^First~and^Last~take no parameter and give a discrete type.{@&^Succ~and^Pred~take a discrete type and give the same discrete type.{{{@'Also remember that a type name followed by^'~denotes an^attribute`:{@9Put(%Character'`Val(7)); -- beep{{@0A type name followed by^( )~denotes^conversion`:{@?G := F +^Float(`I%)`;{{@,And a type name followed by^'( )~denotes^qualification`:{@:Display(%Rainbow_Color'(`Red%)`);{}b[ 221B219]@*1.  Rainbow_Color'First@-5.  Rainbow_Color'Pred{{@*2.  Rainbow_Color'Image@-6.  Rainbow_Color'Succ{{@*3.  Rainbow_Color'Last@.7.  Rainbow_Color'Val{{@*4.  Rainbow_Color'Pos@/8.  Rainbow_Color'Value{{{Which one of the above attributes would you use to convert from the String{%"Blue"~to the Rainbow_Color^Blue`?{}Please press 1, 2, 3, 4, 5, 6, 7, or 8, or B to go back.[82221223222432234225522662267227B220]%You're right!~ The attribute^Value~converts from String to a discrete type.{{@5^Rainbow_Color'Value("Blue")~is^Blue`.{}q[ 228B221Q221]No,^First~and^Last~take no parameter and return a discrete type:{{@)^Rainbow_Color'First~is^Red~and^Rainbow_Color'Last~is^Violet`.{{You want to convert from a String parameter to a discrete type.{}q[ 228B221Q221]No,^Image~converts from a discrete type to String:{{@5^Rainbow_Color'Image(Blue)~is^"BLUE"`.{{You want to convert from String to a discrete type.{}q[ 228B221Q221]No,^Pos~converts from a discrete type to an integer:{{@8^Rainbow_Color'Pos(Blue)~is^4`.{{You want to convert from String to a discrete type.{}q[ 228B221Q221]No,^Pred~and^Succ~take a discrete type parameter and return the same discrete{type.{{  ^Rainbow_Color'Pred(Blue)~is^Green~and^Rainbow_Color'Succ(Blue)~is^Indigo`.{{You want to convert from String to a discrete type.{}q[ 228B221Q221]No,^Val~converts from an integer to a discrete type.{{@8^Rainbow_Color'Val(4)~is^Blue`.{{You want to convert from String to a discrete type.{}q[ 228B221Q221]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Recursion and Assignment 4{{@#The Format of an Ada Program@-Subprograms and Packages{{@#Generic Instantiation and@0Access Types, User Defined Types,{@&Assignment 1@=and Derived Types{{@#Simple Declarations and Simple@+Exceptions, Text_IO, and{@&Attributes@?Assignment 5{{%>  OPERATORS, CONTROL CONSTRUCTS, AND~@&Generics, Tasking, and Assignment 6{@%^ASSIGNMENT 2`{@LMore Records and Types{@#Records, Arrays, and Assignment 3{@LAdvanced Topics{}b[ 229B221]@COPERATORS{{The four basic arithmetic operators,^+`,^-`,^*`, and^/`, can be used with any{integer or floating point type.  (We'll learn about fixed point types in the{section on More Records and Types.)  The exponentiation operator,^**`, takes a{base of type Integer or Float, and an exponent of subtype Natural.  It returns{the same type as the base.  Although Float ** Float isn't part of the Ada 83{language, a vendor may supply a math package with an Ada compiler to increase{its sales appeal.  If the math package includes a function "**" to raise a{Float base to a Float exponent, then our programs can^with~and^use~the package{and then use^**~between two Floats.{{Similarly, Exp, Log, and the trig functions don't come with Ada 83, but the{vendor may supply them in a math package.{{Ada 9X comes with a package called Numerics.Elementary_Functions that provides{Float ** Float, Exp, Log, and the trig functions.  See Appendix C of the Ada 9X{LRM.{}b[ 230B228]The six^relational operators~are:{{%<~ less than@1^>~ greater than@1^=~ equal to{{%<=~less than or equal to@%^>=~greater than or equal to@%^/=~not equal to{{Five of these are the same as in Basic and Pascal, but the Ada symbol for "not{equal to" is^/=`, because^<>~means^box`.  The relational operators compare two{objects of the same type, and return a result of type Boolean.{{All of the above operators are used^between~two objects (e.g.,^B := A + B;`).{Of course,^+~and^-~may also be^unary~operators (%B := +A;  A := -A;`).{{The operators^and`,^or`, and^xor~are used between two Boolean objects, and^not~is{a unary Boolean operator.  Naturally,^xor~is the exclusive or: ^A xor B~is True{if either A or B is True, but not if both are True.{}b[ 231B229]The numeric operator^abs~takes the absolute value of an Integer or Float.{Since^abs~is a unary operator like^-`, we can write^B := abs A;`.  We may, but{don't have to, use parentheses and write^B := abs(A);`.{{When used between two integers,^/~gives only the integer part of the quotient.{Thus^9/4~is 2.  The operators^mod~(modulo) and^rem~(remainder) are very similar{to each other, and are used between two integers to give only the remainder in{division.  For example,^9 mod 4~is 1.  For positive parameters,^mod~and^rem~are{the same.  But with negative parameters,^mod~gives the sign of the denominator{while^rem~gives the sign of the numerator.  Many programmers simply ignore^rem`{and use^mod~exclusively.{{The operator^&~concatenates arrays, so we'll discuss it later.  We'll learn{that a String is one type of array (an array of Characters), so^&~can{concatenate Strings.{}b[ 232B230]@BRANGE TESTS{{The reserved word^in~tests if something is inside a range, and returns a{Boolean result.  For example, if Lower, Upper, and X are declared as Floats, we{need not write{{@0^if X >= Lower and X <= Upper then~...^end if;`{{This can be expressed more clearly as{{@3^if X in Lower .. Upper then~...^end if;`{{We can also write^not in`.  Thus^X not in Lower .. Upper~is a clear way of{expressing^X < Lower or X > Upper`.{{A subtype may be substituted for the range to the right of^in`.  If Day_Subtype{is defined as a subtype of Integer, and D is an Integer, then we can write{%D in Day_Subtype`.{}b[ 233B231]If we have the following declarations:{{@=B@': Boolean;{@=A, X, Y : Character;{{then which^one~of the following is^illegal`?{{@71.@$B := X <> Y;{{@72.@$B := A in X .. Y;{{@73.@$B := A = X and X = Y;{}Please press 1, 2, or 3, or B to go back.[123422353236B232]@=B@': Boolean;{@=A, X, Y : Character;{{{@6^1.@$B := X <> Y;`{{@72.@$B := A in X .. Y;{{@73.@$B := A = X and X = Y;{{{%You're right!~ Number 1 is illegal because^<>~should be^/=`.{}q[ 237B233Q233]@=B@': Boolean;{@=A, X, Y : Character;{{{@71.@$B := X <> Y;{{@72.@$B := A in X .. Y;{{@73.@$B := A = X and X = Y;{{{No, number 2 is legal.  The reserved word^in~tests to see if A is within the{range X to Y.  It returns a Boolean result, which is stored in B.{}q[ 237B233Q233]@=B@': Boolean;{@=A, X, Y : Float;{{{@71.@$B := X <> Y;{{@72.@$B := A in X .. Y;{{@73.@$B := A = X and X = Y;{{{No, number 3 is legal.  Parentheses aren't necessary here, but it's the same as{if we had written{{@;B := (A = X) and (X = Y);{{In two places^=~returns a Boolean result.  Then^and~takes the two Boolean{results and also returns a result of type Boolean.  That final result is then{stored in B.{}q[ 237B233Q233]@<THE SHORT CIRCUIT FORMS{{Suppose that^N~(for numerator) and^D~(for denominator) are Floats, and we want{to execute a block of code if the quotient is 10.0 or greater.  We could write{{@:^if N/D >= 10.0 then`{@>-----;{@>-----;  (block of code){@>-----;{@:^end if;`{{However, we realize that if^D~is 0.0, the program will raise a Numeric_Error or{Constraint_Error trying to compute^N/D`.  If the denominator is zero, we{consider the quotient to be very large, so we want to execute the block of code{when^D~is zero.  Our second attempt might be{{@9if^D = 0.0 or N/D >= 10.0~then{@<-----;{@<-----;  (block of code){@<-----;{@9end if;{}b[ 238B233]@9if^D = 0.0 or N/D >= 10.0~then{@<-----;{@<-----;  (block of code){@<-----;{@9end if;{{Here we^hope~that^N/D~won't be evaluated if^D~is zero.  We figure that the{compiler should be smart enough to know that if the expression before^or~is{True, then the whole expression must be True, so the expression to the right of{%or~needn't be evaluated.  However, there's no guarantee that the compiler will{write code to skip the evaluation of the second expression when the first is{True.  An optimizing compiler just might, for some unknown reason, even decide{that the expression on the right should be evaluated first.{{However, with the form^or else`, Ada can bypass (or "short circuit") evaluating{the expression on the right when the one on the left is true:{{@6if D = 0.0^or else~N/D >= 10.0 then{@9-----;{@9-----;  (block of code){@9-----;{@6end if;{}b[ 239B237]@6if D = 0.0^or else~N/D >= 10.0 then{@9-----;{@9-----;  (block of code){@9-----;{@6end if;{{Ada guarantees that the expression to the left of^or else~will be evaluated{first.  If this expression is True, the entire expression must be True, and{it's guaranteed that the second expression won't be evaluated.  If the first{expression is False, then of course the second expression must be evaluated to{determine if the entire expression is True.  Thus the code above will never try{to divide by zero.  If^D~is zero, the expression on the left is True.  The{expression on the right won't be evaluated in that case.{{There's another "short circuit" form called^and then`.  If the expression to{the left of^and then~is False, the whole expression must be False, and the{expression on the right won't be evaluated.  If the expression on the left is{True, then the expression on the right must be evaluated to determine the value{of the entire expression.  Suppose this time that we want to execute a block of{code if^N/D~is^less than~10.0.  If the denominator is zero, we consider the{quotient to be very large, and we don't want to execute the block of code in{that case.  We can write the following:{}b[ 240B238]@6if D /= 0.0^and then~N/D < 10.0 then{@9-----;{@9-----;  (block of code){@9-----;{@6end if;{{Again this protects us from trying to divide by zero.  If^D~is zero, the{expression on the left is False.  The second expression won't be evaluated in{that case.{{After we discuss arrays, we'll see how the short circuit forms can prevent us{from using out-of-range subscripts.  And when we learn about access types,{we'll see how the short circuit forms can keep us from dereferencing a null{pointer.  That means trying to access "the object pointed to" when there's no{such object.{{Remember,^and then~evaluates the second expression only if the first expression{is True;^or else~evaluates the second expression only if the first is False.{}b[ 241B239]Assume that^N~has been declared^Float`, and that our program^with`s and^use`s a{math package with a square root function called^Sqrt`.  Naturally, we don't want{to call^Sqrt~with a negative parameter.  Which of the following would be more{appropriate?{{{@+1.@$if N >= 0.0^and then~Sqrt(N) > 1.618 then ...{{@+2.@$if N >= 0.0^or else~ Sqrt(N) > 1.618 then ...{}Please press 1 or 2, or B to go back.[12422243B240]@*^1.@$if N >= 0.0 and then Sqrt(N) > 1.618 then ...`{{@+2.@$if N >= 0.0 or else  Sqrt(N) > 1.618 then ...{{{%You're right!~ We want the second expression to be evaluated only if the first{expression is True, so we use^and then`.{}q[ 244B241Q241]@+1.@$if N >= 0.0 and then Sqrt(N) > 1.618 then ...{{@+2.@$if N >= 0.0 or else  Sqrt(N) > 1.618 then ...{{{No, we want the second expression to be evaluated only if the first expression{is True, so we use^and then`.{}q[ 244B241Q241]@?CONTROL CONSTRUCTS{{You're almost ready to write your own Ada program in an Outside Assignment, but{first we need to discuss the control constructs.{{Ada encourages structured programming by providing control constructs such as{{@9block^if`s with^elsif`s and^else`{@8^while~loops{@8^for~loops{@8^case~statements{{Ada also provides a^goto~statement, but it's seldom if ever needed.  That's{because the constructs above handle the flow of control more clearly, making{the program easier to read.  With the constructs above, we know how control{reaches each statement.  When^goto`s are used, there can be many paths to a{statement, and we're not sure how control got there.{{Let's look at the above control constructs, and the^goto~statement, one at a{time.  Discussion of the^declare~statement and Ada "blocks" is postponed until{we cover exception handlers.{}b[ 245B241]@ATHE "IF" BLOCK{{@9^if~A >= B and C = A + D^then`{@=-----;{@=-----;  (block of code){@=-----;{@9^end if;`{{In Ada, every^if~introduces a block of code that ends with^end if;`.  There are{no exceptions; every^if~always has an^end if;`.  The condition is followed by{%then`, and it can be any expression with a Boolean result.  The above example{is valid if A, B, C, and D are suitably declared.  Each statement in the block{of code, including the last, has a semicolon.  Note that^end if;~is two{reserved words, so there must be at least one space between them.  All Ada{control constructs, including^if~blocks, can be nested to any depth.{{In Pascal,^if~is designed to execute only one statement conditionally.  If{there's a whole block of statements to be executed conditionally, it has to be{enclosed with "begin ... end" so it will be considered as one statement.  In{Ada, however,^if~always starts a block of code, so "begin ... end" isn't{necessary.  The end of the block is always marked by^end if;~even if there's{just one statement in the block.{}b[ 246B244]@9^if A >= B and C = A + D then`{@<^-----;`{@<^-----;`{@<^-----;`{@9^elsif G = H + P then`{@<^-----;`{@9^elsif Q > R or S <= T then`{@<^-----;`{@<^-----;`{@9^else`{@<^-----;`{@9^end if;`{{The reserved words^elsif~and^else~are also available; note the unusual spelling{of^elsif`.  In the above example, only one of the four blocks of code will be{executed.  If^A >= B and C = A + D~is True, the first block of code will be{executed and the remaining tests and blocks will be skipped.  Control will{continue after the^end if;`.  If^A >= B and C = A + D~is False, then^G = H + P`{will be tested.  If it's True, the second block, and only that block, will be{executed; otherwise,^Q > R or S <= T~will be tested.  If that's True, the third{block will be executed; otherwise the^else~block will be executed.  If all the{tests are False and there's no^else~block, then no blocks are executed.{}b[ 247B245]if A >= B and C = A + D then@6if A >= B and C = A + D then{@#-----;@L-----;{@#-----;@L-----;{@#-----;@9^THESE~@,-----;{elsif G = H + P then@)^<=@$TWO@$=>~@$else{@#-----;@:^ARE~@-if G = H + P then{elsif Q > R or S <= T then@%^EQUIVALENT!~@,-----;{@#-----;@Lelse{@#-----;@Oif Q > R or S <= T then{else@W-----;{@#-----;@R-----;{end if;@Qelse{@[-----;{@Xend if;{@Uend if;{@Rend if;{{As shown,^elsif~is equivalent to^else~plus^if~...^end if;`.  Although the two{program segments above are equivalent, the one on the left is much clearer.{The example on the left doesn't require multiple^end if;`s at the bottom, and{the indentation emphasizes that only one of the four blocks of code will be{executed.{}b[ 248B246]@>D, N : Integer := 1;{@>...{@>if D = 0 then{@AOne;{@>elsif N/D = 1 then{@ATwo;{@>elsif D = 1 then{@AThree;{@>else{@AFour;{@>end if;{{In this segment of code, which procedure(s) will be called?{{@21.  Procedure One will be called.{@22.  Procedure Two will be called.{@23.  Procedure Three will be called.{@24.  Procedure Four will be called.{@25.  Procedures Two and Three will be called.{}Please press 1, 2, 3, 4, or 5, or B to go back.[22491250325142525253B247]@>D, N : Integer := 1;{@>...{@>if D = 0 then{@AOne;{@=^elsif N/D = 1 then`{@@^Two;`{@>elsif D = 1 then{@AThree;{@>else{@AFour;{@>end if;{{%You're right!~ The first test, D = 0, is False, so the second test is made.{N/D = 1 is True, so Two is called.  Since only one block of code is executed in{an^if~block, the remaining tests are not done.{}q[ 254B248Q248]@>D, N : Integer := 1;{@>...{@>if D = 0 then{@AOne;{@>elsif N/D = 1 then{@ATwo;{@>elsif D = 1 then{@AThree;{@>else{@AFour;{@>end if;{{No, both D and N are initialized to 1, so the first test, D = 0, is False and{the second test is made.  The block that's executed is the first block{following a test that's True.{}q[ 254B248Q248]@>D, N : Integer := 1;{@>...{@>if D = 0 then{@AOne;{@>elsif N/D = 1 then{@ATwo;{@>elsif D = 1 then{@AThree;{@>else{@AFour;{@>end if;{{No, both D and N are initialized to 1, so the second test, N/D = 1, is True.{The block that's executed is the^first~block following a test that's True.{Once a block is executed, no further tests in that^if~block are made.  Thus,{Three isn't called even though D = 1 is True.{}q[ 254B248Q248]@>D, N : Integer := 1;{@>...{@>if D = 0 then{@AOne;{@>elsif N/D = 1 then{@ATwo;{@>elsif D = 1 then{@AThree;{@>else{@AFour;{@>end if;{{No, both D and N are initialized to 1, so the second test, N/D = 1, is True.{The block that's executed is the first block following a test that's True.  The{%else~block is executed only if all the tests are False.{}q[ 254B248Q248]@>D, N : Integer := 1;{@>...{@>if D = 0 then{@AOne;{@>elsif N/D = 1 then{@ATwo;{@>elsif D = 1 then{@AThree;{@>else{@AFour;{@>end if;{{No, although N/D = 1 and D = 1 are both True, only^one~block of code in an^if`{block is executed.  The block that's executed is the^first~block following a{test that's True.{}q[ 254B248Q248]@A"WHILE" LOOPS{{@>^while~I < 10^loop`{@B-----;{@B-----;{@B-----;{@>^end loop;`{{The^while~loop first evaluates the Boolean expression (%I < 10~in this example).{If it's False, the block of code isn't executed at all, and execution continues{after the^end loop;`.  If it's True, the block of code is executed and then the{Boolean condition is again evaluated.  If the condition is still True, the{block is executed again and the Boolean expression is evaluated again, and so{forth.  When the Boolean expression becomes False, the block of code is skipped{and execution continues after the^end loop;`.{}b[ 255B248]To create an "infinite loop," it isn't necessary to write^while True loop`.  We{simply write^loop`, as follows:{{@B^loop`{@F-----;{@F-----;{@F-----;{@B^end loop;`{{Ada doesn't have a "repeat ... until" loop, with the test at the bottom.{However, we can create a loop that's equivalent to a "repeat ... until" loop by{using an infinite loop with an^exit~statement, to be covered very soon.{{}b[ 256B254]@C"FOR" LOOPS{{@(^for Ix in 1 .. 10 loop~@'^for Ix in reverse 1 .. 10 loop`{@+^-----;~@7^-----;`{@+^-----;~@7^-----;`{@(^end loop;~@4^end loop;`{{Here are two sample^for~loops.  We need not declare the index (%Ix~in these{examples) in the declarative region of the program; an index of a^for~loop{declares itself.  In these examples,^Ix~comes into existence at the^for`{statement and goes out of existence at^end loop;~the index isn't available{outside the loop.  If the name^Ix~happens to be used in the declarative region,{it's a different^Ix`.  Inside the loop^Ix~refers to the index; there the name^Ix`{is said to^hide~any^Ix~that might be mentioned in the declarative region.{{The index variable may not be modified.  In these examples,^Ix~may not appear{on the left side of an assignment statement, etc.{{In the first example above, the block of statements is executed ten times, with{Ix equal to 1, then 2, then 3, etc., up to 10.  In the second example, Ix{starts at 10 and counts down to 1.  Note that the range is still written{%1 .. 10`, but the keyword^reverse~precedes the range.{}b[ 257B255]The index of a^for~loop can have any discrete type (integer or enumeration{type).  It can't be of type Float.  For example, if we write{{@#type Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);{@#type Traffic_Light_Color is (Red, Amber, Green);{{then we can write^for Ix in Red .. Blue loop`, and the compiler will know that{%Ix~must be of type Rainbow_Color.  Similarly, the type of^Ix~will be{Traffic_Light_Color if we write^for IX in Red .. Amber loop`.  But the compiler{can't handle^for Ix in Red .. Green loop~because of the ambiguity.  In this{case we have to specify the type.  For example, we could write either of these:{@1^for Ix in Rainbow_Color'(Red) .. Green loop`{@/^for Ix in Rainbow_Color range Red .. Green loop`{{Because the index can have any discrete type, there's no STEP clause in Ada.{One might increment an Integer index by 2, but we couldn't add 2 to Red.  For{uniformity, no STEP clause is available, even if the index type is Integer.{{Ranges may contain expressions.  If A, B, C, and D are Integer variables, we{can say^for I in A + B .. C + D loop~or^for I in reverse A + B .. C + D loop`.{In both cases the range is null if C + D is less than A + B.  That won't cause{an error; the loop is simply skipped when the range is null.{}b[ 258B256]If we have{{@#type Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);{@#J : Integer := 5;{{which one of these statements is^illegal`?{{{@81.  for I in -J .. J loop{{@82.  for I in J .. Violet loop{{@83.  for I in Violet .. Red loop{}Please press 1, 2, or 3, or B to go back.[225912603261B257]@#type Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);{@#J : Integer := 5;{{@81.  for I in -J .. J loop{{@7^2.  for I in J .. Violet loop`{{@83.  for I in Violet .. Red loop{{{%You're right!~ Number 2 is illegal because the expressions before and after the{"%..`" must be of the same type.{}q[ 262B258Q258]@#type Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);{@#J : Integer := 5;{{@81.  for I in -J .. J loop{{@82.  for I in J .. Violet loop{{@83.  for I in Violet .. Red loop{{{No, number 1 is legal.  The expressions on both sides of^..~have the same type.{%I~will be of type Integer and will take 11 values, from -5 to 5.{}q[ 262B258Q258]@#type Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);{@#J : Integer := 5;{{@81.  for I in -J .. J loop{{@82.  for I in J .. Violet loop{{@83.  for I in Violet .. Red loop{{{No, number 3 is legal.  The expressions on both sides of^..~have the same type.{The loop will be skipped because Red is less than Violet, giving a null range.{But the syntax is legal.  To make^I~start at Violet and count down to Red, we{would write{{@6for I in reverse Red .. Violet loop{}q[ 262B258Q258]@>THE "EXIT" STATEMENT{{@)for I in 1 .. 10 loop@,for I in 1 .. 10 loop{@,J := 0;@:J := 0;{@,loop@=loop{@/J := J + 1;@6J := J + 1;{@.^if A(I, J) = 0 then`{@1^exit;~@7^exit when A(I, J) = 0;`{@.^end if;`{@,end loop;@8end loop;{@,B(I) := J;@7B(I) := J;{@)end loop;@8end loop;{{The statement^exit;~exits the innermost loop.  In the example at the left,{%exit;~transfers control to the statement^B(I) := J;`.  Since^exit;~is often the{only statement in an^if~block,^exit when~is available to abbreviate an^if~block{with^exit;~as its only statement.  The two examples above are equivalent.{{Although^exit;~can appear anywhere inside any kind of loop, well-structured{Ada programs use only^exit when`, and then only as the last statement of an{otherwise infinite loop, as shown at the right above.  This simulates a{"repeat ... until" loop, which isn't directly available in Ada.{}b[ 263B258]@6^Outer:`{@6^for I in 1 .. 10 loop`{@:J := 0;{@:loop{@=J := J + 1;{@<^exit Outer when A(I, J) = 0;`{@:end loop;{@:B(I) := J;{@6^end loop Outer;`{@7K := J;{{An^exit~statement can exit other than the innermost loop by^naming~the loop to{be exited.  In this example, the^for~loop is named^Outer`.  A loop name is any{Ada identifier, and is followed by a colon.  Of course,^Outer:~could have been{placed on the same line as the^for~statement.  When a loop is named, the^end{loop~statement must repeat the name of the loop.  The^exit~statement can then{name the loop to be exited, as in^exit Outer;~or^exit Outer when A(I, J) = 0;`.{In this example, the^exit~statement transfers control to the statement^K := J;`,{not to^B(I) := J;`.{{Well-structured programs don't use^exit~to leave any loop except the innermost{loop.  The above example isn't well-structured.{}b[ 264B262]@@LABELS AND GOTOS{{@7Outer:{@7for I in 1 .. 10 loop{@:J := 0;{@:loop{@=J := J + 1;{@=exit Outer when A(I, J) = 0;{@:end loop;{@:B(I) := J;{@7end loop Outer;{@7K := J;{{Although an Ada loop name looks exactly like a Pascal label,^Outer:~is^not~a{label, and the program can't^goto Outer`.  An Ada label looks like this:{{@B^<< Jail >>`{{The^<<~...^>>~makes the label very conspicuous, whether it's on the same line{as a statement or on a line by itself.  The program can then say^goto Jail;`.{Like all reserved words,^goto~can't contain a space.  Well-structured Ada{programs don't need^goto`s and labels, so their use is very rare.{}b[ 265B263]@8I_Loop:@#for I in 1 .. 10 loop{@EJ := 0;{@8J_Loop:@&loop{@HJ := J + 1;{@Hexit;{@Eend loop J_Loop;{@EL := J;{@Bend loop I_Loop;{@BM := J;{{{In the program segment above, which statement will be executed after^exit;`?{{@;1.  L := J;{{@;2.  M := J;{{@;3.  for I in 1 .. 10 loop{}Please press 1, 2, or 3, or B to go back.[126622673268B264]@8I_Loop:@#for I in 1 .. 10 loop{@EJ := 0;{@8J_Loop:@&loop{@HJ := J + 1;{@Hexit;{@Eend loop J_Loop;{@D^L := J;`{@Bend loop I_Loop;{@BM := J;{{{%You're right!~ When used without a name,^exit;~leaves the innermost loop, so{the next statement executed is^L := J;`.{}q[ 269B265Q265]@8I_Loop:@#for I in 1 .. 10 loop{@EJ := 0;{@8J_Loop:@&loop{@HJ := J + 1;{@Hexit;{@Eend loop J_Loop;{@EL := J;{@Bend loop I_Loop;{@BM := J;{{{No, when used without a name,^exit;~leaves the^innermost~loop.{}q[ 269B265Q265]@8I_Loop:@#for I in 1 .. 10 loop{@EJ := 0;{@8J_Loop:@&loop{@HJ := J + 1;{@Hexit;{@Eend loop J_Loop;{@EL := J;{@Bend loop I_Loop;{@BM := J;{{{No, when used without a name,^exit;~leaves the innermost loop.  The next{statement executed will be the first statement after the end of the innermost{loop.{}q[ 269B265Q265]@>THE "CASE" CONSTRUCT{{%case C is~@7In this example, assume that^C~is of type{  ^when '*' =>~@2Character.  The expression being tested (%C`),{@%^-----;~@4must have a discrete type: integer or{@%^-----;~@4enumeration type.  The^case~construct must{  ^when '#' | '$' =>~@,handle all possible values, but^when others~is{@%^-----;~@4available.  If no action is desired for{@%^-----;~@4characters not mentioned, we can write^when`{@%^-----;~@3^others => null;`.  The Ada statement^null;~does{  ^when '0' .. '9' =>~@+nothing.  Note that the vertical bar can be{@%^-----;~@4used to apply several cases to one block of{  ^when 'A'..'Z' | 'a'..'z' =>~  code, and that ranges can be used.  Here, if^C`{@%^-----;~@4is '*', the first block is executed; if it's{@%^-----;~@4'#' or '$', the second block is executed.  If{@%^-----;~@4it's a digit, the third block is executed, and{  ^when others =>~@/if it's a letter (upper or lower case), the{@%^-----;~@4fourth block is executed.  If^C~is anything{@%^-----;~@4else, the fifth (last) block of code is{%end case;~@7executed.{}b[ 270B265]case C is{@#when '*' =>@8if C = '*' then{@&-----;@=-----;{@&-----;@=-----;{@#when '#' | '$' =>@2elsif C = '#' or C = '$' then{@&-----;@=-----;{@&-----;@=-----;{@&-----;@=-----;{@#when '0' .. '9' =>@1elsif C in '0' .. '9' then{@&-----;@=-----;{@#when 'A'..'Z' | 'a'..'z' =>@(elsif C in 'A'..'Z' or C in 'a'..'z' then{@&-----;@=-----;{@&-----;@=-----;{@&-----;@=-----;{@#when others =>@5else{@&-----;@=-----;{@&-----;@=-----;{end case;@=end if;{{The two examples above are equivalent.  In both cases only one block of code{will be executed.  By the way, the symbol^=>~is read "choose" (or sometimes{"arrow"), and may not contain a space.{}b[ 271B269]If we have{{@#type Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);{@#type Traffic_Light_Color is (Red, Amber, Green);{@#F : Float range 0.0 .. 2.0;{@#R : Rainbow_Color;{@#T : Traffic_Light_Color;{{then which^one~of the following program segments is^legal`?{{@,1:@<2:@93:{{ case R is@7case F is@4case T is{@$when Red | Green =>@-when 0.0 .. 1.0 =>@+when Red =>{@'-----;@:-----;@7-----;{@$when Blue .. Violet =>@*when others =>@/when others =>{@'-----;@:-----;@7-----;{ end case;@7end case;@4end case;{{}Please press 1, 2, or 3, or B to go back.[327212732274B270]@#type Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);{@#type Traffic_Light_Color is (Red, Amber, Green);{@#F : Float range 0.0 .. 2.0;{@#R : Rainbow_Color;{@#T : Traffic_Light_Color;{{@,1:@<2:@8^3:`{{ case R is@7case F is@3^case T is`{@$when Red | Green =>@-when 0.0 .. 1.0 =>@*^when Red =>`{@'-----;@:-----;@6^-----;`{@$when Blue .. Violet =>@*when others =>@.^when others =>`{@'-----;@:-----;@6^-----;`{ end case;@7end case;@3^end case;`{{%You're right!~ Number 1 is illegal because it doesn't account for all possible{values of^R`, and number 2 is illegal because^F~doesn't have a discrete type.{}q[ 275B271Q271]@#type Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);{@#type Traffic_Light_Color is (Red, Amber, Green);{@#F : Float range 0.0 .. 2.0;{@#R : Rainbow_Color;{@#T : Traffic_Light_Color;{{@,1:@<2:@93:{{ case R is@7case F is@4case T is{@$when Red | Green =>@-when 0.0 .. 1.0 =>@+when Red =>{@'-----;@:-----;@7-----;{@$when Blue .. Violet =>@*when others =>@/when others =>{@'-----;@:-----;@7-----;{ end case;@7end case;@4end case;{{No, number 1 is illegal because it doesn't account for all the possible values{of^R`.{}q[ 275B271Q271]@#type Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);{@#type Traffic_Light_Color is (Red, Amber, Green);{@#F : Float range 0.0 .. 2.0;{@#R : Rainbow_Color;{@#T : Traffic_Light_Color;{{@,1:@<2:@93:{{ case R is@7case F is@4case T is{@$when Red | Green =>@-when 0.0 .. 1.0 =>@+when Red =>{@'-----;@:-----;@7-----;{@$when Blue .. Violet =>@*when others =>@/when others =>{@'-----;@:-----;@7-----;{ end case;@7end case;@4end case;{{No, number 2 is illegal because^F~doesn't have a discrete type.{}q[ 275B271Q271]@:BRIEF OVERVIEW OF FUNCTIONS{{@.procedure Funct_Demo is{@1X : Float := 1.2;{@1Y : Float;{@0^function Twice(Dummy : in Float) return Float is`{@3^Answer : Float;`{@0^begin`{@3^Answer := Dummy * 2.0;`{@3^return Answer;`{@0^end Twice;`{@.begin{@1Y := Twice(X);{@.end Funct_Demo;{{Let's look briefly at functions so we can do Outside Assignment 2; later, we'll{cover functions and procedures in detail.  Here procedure Funct_Demo locally{declares a function Twice.  Twice can be called only from within Funct_Demo:{%Y := Twice(X);`.  The function specification gives the name (Dummy), mode (in),{and type (Float) of any formal parameters, or "dummy arguments."  For{functions, the mode of all parameters must be^in`, never^out~or^in out`.  The{function specification also gives the type being^return`ed, in this case Float.{}b[ 276B271]@.procedure Funct_Demo is{@1X : Float := 1.2;{@1Y : Float;{@1function Twice(Dummy : in Float) return Float is{@4Answer : Float;{@1begin{@4Answer := Dummy * 2.0;{@3^return Answer;`{@1end Twice;{@.begin{@1Y := Twice(X);{@.end Funct_Demo;{{The function body must have^return~followed by an expression of the right type.{In well-structured functions, this is the last statement before^end`.  We don't{return a value by placing the name of the function in an assignment statement,{as in Fortran.  Of course, function Twice could be written more simply as{{@0function Twice(Dummy : in Float) return Float is{@0begin{@3return Dummy * 2.0;{@0end Twice;{}b[ 277B275]@)procedure Funct_Demo is{@,X : Float := 1.2;{@,Y : Float;{@+^function Twice(Dummy : in Float) return Float is separate;`{@)begin{@,Y := Twice(X);{@)end Funct_Demo;{{@(^separate (Funct_Demo)`{@(^function Twice(Dummy : in Float) return Float is`{@)begin{@,return Dummy * 2.0;{@)end Twice;{{The function can be placed in a separate file and compiled later.  Here the{calling program can be compiled once, and later the function can be edited and{recompiled as often as desired. ^Twice~is still local to^Funct_Demo`.  The{phrase^separate (Funct_Demo)~tells Ada that this subprogram is part of the{previously compiled unit^Funct_Demo`.  It's as if the function were cut out and{"pasted" where the calling program says^function Twice~...^is separate;`.  Ada{can still compile the call^Y := Twice(X);~because the calling program contains{the specification of the function.{}b[ 278B276]@.OUTSIDE ASSIGNMENT 2 - EXERCISE IN ENUMERATION TYPES{{Separate compilation is the basis of our next Outside Assignment.  The function{we want you to write is completely specified by these two lines of Ada:{{@%^type Triangle is (Equilateral, Isosceles, Scalene, Not_a_Triangle);`{@%^function Tritype(Len1, Len2, Len3 : in Integer) return Triangle;`{{From these two lines, it's obvious that your function must decide whether three{integers, representing the lengths of the sides of a triangle, in fact{represent an equilateral triangle, an isosceles triangle, a scalene triangle,{or no triangle at all.  (An equilateral triangle has three equal sides; an{isosceles triangle has only two equal sides.  A scalene triangle has sides of{three different lengths, and the integers -1, 0, 5 represent no triangle.){{A test driver for your function is already written, and is in the file{%TRITEST.ADA`.  A listing starts on page 10 of your printed course notes.  You{need not understand the test driver.  It's sufficient to know that if your{function passes all the tests, the message "Congratulations, you completed the{assignment!" is shown.  For any failed tests, the test driver displays the test{case, the answer from your function, and the correct answer.  This will help{you in debugging your function.{}b[ 279B277]The test driver, which is the main program, contains these declarations:{{  type Triangle is (Equilateral, Isosceles, Scalene, Not_a_Triangle);{  function Tritype(Len1, Len2, Len3 : in Integer) return Triangle is separate;{{This allows you to edit and recompile your function as often as you like,{without having to recompile the test driver.  Since type^Triangle~is defined in{the calling program, you should^not~define it in your function.{{To get you started, a dummy solution is given in^TRITYPE.DUM`.  You can copy it{and edit the copy to become your real solution.  It looks like this:{{@'-- Dummy solution for Outside Assignment 2{@'-- Edit to become your real solution.{@'separate (Tritest){@'function Tritype(Len1, Len2, Len3 : in Integer) return Triangle is{@'begin{@*return Not_a_Triangle;{@'end Tritype;{{If you wish, you may compile this dummy solution before editing it.  Then{you'll see what error messages from the test driver look like.{}b[ 280B278]@'-- Dummy solution for Outside Assignment 2{@'-- Edit to become your real solution.{@&^separate (Tritest)`{@&^function Tritype(Len1, Len2, Len3 : in Integer) return Triangle is`{@&^begin`{@*return Not_a_Triangle;{@&^end Tritype;`{{When you do edit the function, you'll probably want to remove or change the{first two comment lines.  Don't change the lines^highlighted~above.  You may{want to create a new variable of type Triangle, and return that variable{instead of the constant Not_a_Triangle at the end of your function:{{@'separate (Tritest){@'function Tritype(Len1, Len2, Len3 : in Integer) return Triangle is{@)^Answer : Triangle;`{@'begin{@*if ... end if;{@)^return Answer;`{@'end Tritype;{{However, that's not the only way to solve the problem, just a suggestion.{}b[ 281B279]Here are the steps to follow for Outside Assignment 2.  They're also in your{printed course notes on page 12:{{1.  Compile the test driver TRITEST.ADA.  Also, make a copy of the dummy{@$solution by typing^COPY TRITYPE.DUM TRITYPE.ADA`.  You need do this step{@$only once.{{2.  Edit TRITYPE.ADA to become your real solution.  You may skip this step the{@$first time through, to see error messages from the test driver.{{3.  Compile your solution TRITYPE.ADA.  If the compiler finds errors, go back{@$to step 2.{{4.  Link with the name of the main program Tritest.  Then execute.  If the test{@$driver displays error messages, go back to step 2.{{5.  When the message "Congratulations, you completed the assignment!" is{@$displayed, you'll have a chance to compare your solution with ours.{}b[ 282B280]Remember that a function can't change the values of its parameters (in this{case, Len1, Len2, and Len3), because function parameters are always of mode^in`.{{This assignment should be a simple exercise in enumeration types and the{control constructs.  Our solution easily fits on one screen.  If you find your{solution getting long and difficult, you should probably think through the{problem again.  See if there's a simple way to test for the four possible{answers.{{Please type X to exit^ADA-TUTR~temporarily, and try Outside Assignment 2.  Work{at your own pace; there's no deadline.  Good luck!{}Please type X to exit, a space to go on, or B to go back.[ 283B281]@-^Congratulations on Completing Outside Assignment 2!`{{Our solution is in^TRITYPE.ANS`.  It looks like this:{{-- Our solution to Outside Assignment 2:{separate (Tritest){function Tritype(Len1, Len2, Len3 : in Integer) return Triangle is{@#Answer : Triangle;{begin{@#if Len1 + Len2 <= Len3  or Len1 + Len3 <= Len2  or Len2 + Len3 <= Len1  then{@&Answer := Not_a_Triangle;{@#elsif  Len1 = Len2  and  Len2 = Len3  then{@&Answer := Equilateral;{@#elsif  Len1 = Len2  or  Len2 = Len3  or  Len1 = Len3  then{@&Answer := Isosceles;{@#else{@&Answer := Scalene;{@#end if;{@#return Answer;{end Tritype;{}b[ 284B282]Note that it isn't necessary to include tests for sides <= 0, because if any{side <= 0, one of the three tests in the following would have to catch that:{{if  Len1 + Len2 <= Len3  or  Len1 + Len3 <= Len2  or  Len2 + Len3 <= Len1  then{@#Answer := Not_a_Triangle;{{However, most students include tests for sides <= 0, so if you did, don't feel{bad.  It doesn't do any harm.{{You must have realized by now that it's impossible to draw a triangle with{sides 1, 2, and 3.  The sum of any two sides must be greater than the third.{{There are many correct ways to solve this problem.  Some students make copies{of the three sides and sort them first.  Some initialize Answer to Scalene in{the declarative region and omit the code{{@=else{@@Answer := Scalene;{{If you saw the message "Congratulations, you completed the assignment!" you may{consider your solution correct.  Let's go on to discuss Records and Arrays.{}b[ 285B283]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Recursion and Assignment 4{{@#The Format of an Ada Program@-Subprograms and Packages{{@#Generic Instantiation and@0Access Types, User Defined Types,{@&Assignment 1@=and Derived Types{{@#Simple Declarations and Simple@+Exceptions, Text_IO, and{@&Attributes@?Assignment 5{{@#Operators, Control Constructs, and@'Generics, Tasking, and Assignment 6{@&Assignment 2{@LMore Records and Types{%>  RECORDS, ARRAYS, AND ASSIGNMENT 3`{@LAdvanced Topics{}b[ 286B284]@DRECORDS{{A^record~lets us group several declarations together and refer to them as one:{{@%type Month_Type is (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);{@%subtype Day_Subtype is Integer range 1 .. 31;{@$^type Date is`{@'^record`{@*^Day@#: Day_Subtype;~  -- Naturally, Day_Subtype and{@*^Month : Month_Type;~@#-- Month_Type must be defined{@*^Year  : Integer;~@&-- before type Date is defined.{@'^end record;`{@$^USA : Date;`{{In this example,^USA~has three parts (called "fields"): ^USA.Day`,^USA.Month`,{and^USA.Year`.  The fields of a record can be of any type, including other{records.  Here^USA.Day~is of^type~Integer,^USA.Month~is of type Month_Type, and{%USA.Year~is of type Integer.  The parts of^USA~may be referenced separately:{{@>^USA.Day@#:= 4;`{@>^USA.Month := Jul;`{@>^USA.Year  := 1776;`{}b[ 287B285]@%type Month_Type is (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);{@%subtype Day_Subtype is Integer range 1 .. 31;{@$^type Date is`{@'^record`{@*^Day@#: Day_Subtype;`{@*^Month : Month_Type;`{@*^Year  : Integer;`{@'^end record;`{@$^USA : Date;`{{However,^USA~can also be referenced as one object.  For example, we could have{assigned all three fields in one statement: ^USA := (4, Jul, 1776);`.  Here the{object on the left is of type Date, and the object on the right is called an{%aggregate`.  The aggregate fits the type Date because it contains an Integer, a{Month_Type, and another Integer.  This aggregate is said to use^positional`{notation because its three parts appear in the same order as the three parts of{the record definition:  first Day, then Month, then Year.{{We can specify the parts of an aggregate in any order if we use^named~notation:{%USA := (Month => Jul, Day => 4, Year => 1776);`.  (The symbol^=>~is read "arrow"{and may not contain a space.)  Using named notation often improves program{readability, especially if the names of the fields are well chosen.{}b[ 288B286]@%type Month_Type is (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);{@%subtype Day_Subtype is Integer range 1 .. 31;{@$^type Date is`{@'^record`{@*^Day@#: Day_Subtype;`{@*^Month : Month_Type;`{@*^Year  : Integer;`{@'^end record;`{@$^USA : Date;`{{We can switch from positional to named notation in an aggregate.  But once we{use named notation, the compiler loses track of position, so we can't switch{back to positional.  For example, the following is^legal`:{{@3^USA := (4, Year => 1776, Month => Jul);`{{But the following is^illegal~because positional notation can't follow named:{{@3USA := (4, Year => 1776, Jul); -- illegal{{Record discriminants and record variants will be discussed in the section on{More Records and Types, as will Ada 9X Tagged Records.{}b[ 289B287]@$procedure Record_Exercise is{@'type Month_Type is (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);{@'subtype Day_Subtype is Integer range 1 .. 31;{@'type Date is{@*record{@-Day@#: Day_Subtype;{@-Month : Month_Type;{@-Year  : Integer;{@*end record;{@'D1, D2, D3 : Date; ^-- 1`{@$begin{@'D1 := (Month => Jan, Day => 22, Year => 1983); ^-- 2`{@'D2.Day := 22;{@'D2.Month := 1; ^-- 3`{@'D2.Year := 1983;{@'D3 := D2; ^-- 4`{@$end Record_Exercise;{{Which commented line in the above program is^illegal`?{}Please press 1, 2, 3, or 4, or B to go back.[3290129122924293B288]@&^D2.Month := 1;  -- 3`{{%You're right!~ This statement is illegal, because the types are mixed.{%D2.Month~is of type Month_Type, and^1~is an integer.{}q[ 294B289Q289]@'D1, D2, D3 : Date;  -- 1{{No, this statement is legal, because several objects may be declared in one{statement, if the objects are separated by commas.{}q[ 294B289Q289]@'D1 := (Month => Jan, Day => 22, Year => 1983);  -- 2{{No, this statement is legal, because the fields within the aggregate may appear{in any order when named notation is used.{}q[ 294B289Q289]@'D3 := D2;  -- 4{{No, this statement is legal, because^D3~and^D2~both have the same type:^Date`.{An entire record can be assigned with one statement.{}q[ 294B289Q289]@EARRAYS{{To declare an array in Ada, we specify the^type and range of the subscript`,{followed by the^type of the elements~of the array.  The subscript can have any{discrete type (integer or enumeration), and the elements of the array can be of{any type at all, including records and other arrays.  There are three ways to{declare an array in Ada.  Here are three examples of the most direct, but least{flexible, way (types Rainbow_Color and Date must be defined earlier):{{%A : array(Rainbow_Color range Orange .. Blue) of Date;`{@#-- A four-element array, each element of which is a record with three parts.{@#-- The allowable subscripts are Orange, Yellow, Green, and Blue.  Here{@#-- A(Yellow) is of type Date, and A(Yellow).Year is of type Integer.{%B : array(Integer range -10 .. 10) of Integer;`{@#-- An array of 21 Integers, with Integer subscripts.{%C : array(0 .. 30) of Float;`{@#-- Here (0 .. 30) is understood to mean (Integer range 0 .. 30), and we have{@#-- an array of 31 Floats, with Integer subscripts.`{{A subscript can be an expression; if I is an Integer, we can write^C(2*I)`.  If{a subscript is out-of-range (for example,^A(Red)~or^C(-32)`), the program will{raise a Constraint_Error.{}b[ 295B289]This direct method of declaring arrays is usually used to create single arrays{for table lookup, etc., where there's no need to have several arrays of the{same type.  A better way to declare an array is to specify a type name for the{array itself.  Then several objects can be declared to have that same type.{For example,{{@1^type Vector100 is array(1 .. 100) of Float;`{@1^type Vector300 is array(1 .. 300) of Float;`{@1^D, E, F : Vector100;`{@1^G, H@$: Vector300;`{{Here D, E, and F are all of type^Vector100`, so we can write^D := E;~ and assign{the entire array with one statement.  Similarly, we can write^G := H;`, but not{%G := F;`.{{The example above takes four statements.  An even better way to declare arrays{is to leave the range of the subscript unspecified with the^box~symbol,^<>`,{specifying the range when declaring the objects.  For example,{{@/^type Vector is array(Integer range <>) of Float;`{@/^D, E, F : Vector(1 .. 100);`{@/^G, H@$: Vector(1 .. 300);`{}b[ 296B294]There are two errors to avoid when declaring arrays in this way.  One is to{declare a type with the box symbol for the range of the subscript, and then{fail to specify the range when declaring an object (other than a constant):{{@,^type Vector is array(Integer range <>) of Float;`{@,^D1 : Vector := (2.3, 4.5, 4.0); -- illegal in Ada 83.`{@-D2 :^constant~Vector := (2.3, 4.5, 4.0);^-- legal`{{This error is called^unconstrained array`.  Unconstrained arrays are legal in{formal parameters ("dummy arguments") of procedures and functions, and a{function can^return~an unconstrained array type.  (We'll learn about these{things later.)  But an unconstrained array is illegal when declaring a{variable, because the compiler needs to know the range of the subscript.{{The second example above is illegal in Ada 83, but it is legal in Ada 9X,{because the Ada 9X compiler translates it to{{@3^D1 : Vector(1 .. 3) := (2.3, 4.5, 4.0);`{}b[ 297B295]@3^D1 : Vector(1 .. 3) := (2.3, 4.5, 4.0);`{{In Ada 83, we have to supply the^(1 .. 3)~ourselves.  Either version of Ada{will report an unconstrained array error if we write{{@;^D1 : Vector; -- illegal`{{The other error is to specify the range of the subscript twice: once when{declaring the type and once when declaring the object:{{@1^type Vector100 is array(1 .. 100) of Float;`{@1^D2 : Vector100(1 .. 100);  -- illegal`{{Even if the two ranges agree, this is illegal and is called^doubly constrained{array`.{}b[ 298B296]Arrays may be initialized and assigned with aggregates, and both positional and{named notation may be used.  For example, arrays^A~and^B~are equal here:{{^type Vector5 is array(1 .. 5) of Float;`{^A : constant Vector5 := (2.0, 4.0, 8.0, 16.0, 32.0);`{^B : constant Vector5 := (1 => 2.0, 2 => 4.0, 3 => 8.0, 4 => 16.0, 5 => 32.0);`{{The aggregate must fill the whole array, but the reserved word^others~is{available.  Here's an array of 500 Float variables, all initialized to 0.0:{{@1^type Vector500 is array(1 .. 500) of Float;`{@1^V1 : Vector500 := (others => 0.0);`{{If^others~follows named notation, it's best to qualify the aggregate with the{type name.  Here W(10) = 1.3, W(15) = -30.7, and the rest of the array is 0.0:{{@$^W : Vector500 := Vector500'(10 => 1.3,  15 => -30.7,  others => 0.0);`{{Sometimes we^must~qualify an aggregate when^others~is used with named notation;{at other times it's optional.  The rules (LRM section 4.3.2, paragraphs 4-8){are very complicated.  It's easiest always to qualify an aggregate when^others`{follows named notation, as shown above.{}b[ 299B297]In array aggregates, multiple choices can be denoted with the vertical bar (%|`),{shift-backslash on your keyboard.  In this array, the elements with odd{subscripts are True, while the elements with even subscripts are False:{{@)^type Decade is array(1 .. 10) of Boolean;`{@)^D1 : Decade;`{@*...{@)^D1 := Decade'(1 | 3 | 5 | 7 | 9 => True,  others => False);`{{Here we assigned to D1 with an executable statement for variety; we could also{have initialized D1 in the declarative region with the same aggregate.  Some{people read the vertical bar as "and," others as "or."  One can say, "Elements{1,^and~3, and 5, and 7, and 9 are True," or one can say, "If the subscript is{1,^or~3, or 5, or 7, or 9, the array element is True."{{Array aggregates may also contain ranges.  In this array, elements 1 and 6 - 10{are 1; the rest are 0.  Arrays^L1~and^L2~are equal:{{@(^type List15 is array(1 .. 15) of Integer;`{@(^L1 : List15 := List15'(1 | 6 .. 10 => 1,  others => 0);`{@(^L2 : List15 := (1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0);`{}b[ 300B298]%with Text_IO; use Text_IO;{procedure Array_Quiz is`{  ^package My_Int_IO is new Integer_IO(Integer); use My_Int_IO;`{  ^subtype Capital_Letter is Character range 'A' .. 'Z';{  ^type Set_Of_Letters is array(Capital_Letter) of Boolean;`{  ^Vowels : Set_Of_Letters :=`{@'^Set_Of_Letters'('A' | 'E' | 'I' | 'O' | 'U' => True,  others => False);`{  ^Letter : Capital_Letter;{begin`{  ^Letter := 'E';`{  ^Put(Boolean'Pos(Vowels(Letter)));{end Array_Quiz;`{{@7What will this program display?{{@71.  The program will display 1.{{@72.  The program will display 2.{{@73.  The program will display TRUE.{{@74.  The program will display E.{}Please press 1, 2, 3, or 4, or B to go back.[1301230233034304B299]%with Text_IO; use Text_IO;{procedure Array_Quiz is`{  ^package My_Int_IO is new Integer_IO(Integer); use My_Int_IO;`{  ^subtype Capital_Letter is Character range 'A' .. 'Z';`{  ^type Set_Of_Letters is array(Capital_Letter) of Boolean;`{  ^Vowels : Set_Of_Letters :=`{@'^Set_Of_Letters'('A' | 'E' | 'I' | 'O' | 'U' => True,  others => False);`{  ^Letter : Capital_Letter;{begin`{  ^Letter := 'E';`{  ^Put(Boolean'Pos(Vowels(Letter)));{end Array_Quiz;`{{{%You're right!~ Vowels has 26 elements, with subscripts 'A' through 'Z'.{Vowels(Letter) is Vowels('E'), which is True, and since Ada defines{{@9type Boolean is (False, True);{{and the positions are numbered starting from 0, Boolean'Pos(True) is 1.{}q[ 305B300Q300]with Text_IO; use Text_IO;{procedure Array_Quiz is{@#package My_Int_IO is new Integer_IO(Integer); use My_Int_IO;{@#subtype Capital_Letter is Character range 'A' .. 'Z';{@#type Set_Of_Letters is array(Capital_Letter) of Boolean;{@#Vowels : Set_Of_Letters :={@(Set_Of_Letters'('A' | 'E' | 'I' | 'O' | 'U' => True,  others => False);{@#Letter : Capital_Letter;{begin{@#Letter := 'E';{@#Put(Boolean'Pos(Vowels(Letter)));{end Array_Quiz;{{{No.  Recall that Ada defines{{@9type Boolean is (False, True);{{and that the positions are numbered starting with 0 for the^Pos~attribute.{}q[ 305B300Q300]with Text_IO; use Text_IO;{procedure Array_Quiz is{@#package My_Int_IO is new Integer_IO(Integer); use My_Int_IO;{@#subtype Capital_Letter is Character range 'A' .. 'Z';{@#type Set_Of_Letters is array(Capital_Letter) of Boolean;{@#Vowels : Set_Of_Letters :={@(Set_Of_Letters'('A' | 'E' | 'I' | 'O' | 'U' => True,  others => False);{@#Letter : Capital_Letter;{begin{@#Letter := 'E';{@#Put(Boolean'Pos(Vowels(Letter)));{end Array_Quiz;{{{No.  Indeed Vowels(Letter) is Vowels('E'), which is True, but the program takes{the Boolean'Pos of Vowels(Letter).  Recall that the attribute^Pos~converts from{a discrete type (in this case, Boolean) to an integer.{}q[ 305B300Q300]with Text_IO; use Text_IO;{procedure Array_Quiz is{@#package My_Int_IO is new Integer_IO(Integer); use My_Int_IO;{@#subtype Capital_Letter is Character range 'A' .. 'Z';{@#type Set_Of_Letters is array(Capital_Letter) of Boolean;{@#Vowels : Set_Of_Letters :={@(Set_Of_Letters'('A' | 'E' | 'I' | 'O' | 'U' => True,  others => False);{@#Letter : Capital_Letter;{begin{@#Letter := 'E';{@#Put(Boolean'Pos(Vowels(Letter)));{end Array_Quiz;{{{No.  While Letter is 'E', and Letter appears inside the Put statement, the{parameter of Put is the Boolean'Pos of one element of array Vowels{(specifically, the element whose subscript is 'E').  Recall that the^Pos`{attribute always returns an integer.{}q[ 305B300Q300]In an array declaration or an array type declaration, we may totally omit the{range of the subscript (not even supplying a box), if the type or subtype of{the subscript has a reasonable number of possible values.  (We did that in the{declaration of type Set_Of_Letters in the last question.)  For example, in{{@#type Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);{  ^R : array(Rainbow_Color) of Float;`{{we have an array of seven Floats, because there are seven possible values of{type Rainbow_Color.  Similarly,{{@7^V : array(Character) of Boolean;`{{creates an array of 128 Booleans in Ada 83 and 256 Booleans in Ada 9X.{However,^J : array(Integer) of Float;~is an attempt to declare a very large{array indeed!  In a case like this, we can use a subtype in the subscript{declaration:{{@1subtype Day_Subtype is Integer range 1 .. 31;{@0^J : array(Day_Subtype) of Float;`{{This creates an array of 31 Floats.{}b[ 306B300]The attributes^First~and^Last`, which we've seen with discrete types, can also{be used with array types and with the array names themselves.  For example,{{@0^type My_Vector is array(30 .. 33) of Integer;`{@0^Mv : My_Vector;`{@1...{@0^Mv(30) := 1000;`{@0^Mv(31) := 20;`{@0^Mv(32) := -70;`{@0^Mv(33) := -500;`{{Here^Mv'First~and^My_Vector'First~are both 30. ^Mv'Last~and^My_Vector'Last~are{both 33.  Note that^First~and^Last~refer to the subscripts, not to the values{of the array elements.  Thus^Mv'First~is^not~1000.  To obtain the value of the{first element, we would use^Mv'First~as a^subscript`. ^Mv(Mv'First)~is 1000.{{The attribute^Range~is an abbreviation for^First .. Last`.  It can be used only{with array types and array names, not with discrete types.  Thus^Mv'Range~and{%My_Vector'Range~both mean^30 .. 33`.  We can't write^Integer'Range`, even though{we can write^Integer'First~and^Integer'Last`.  The attribute^Length~is also{available: ^Mv'Length~and^My_Vector'Length~are both 4.{}b[ 307B305]@<MULTIDIMENSIONAL ARRAYS{{Ada arrays may have any number of dimensions, and the subscripts may be of{different discrete types.  For example, assuming Rainbow_Color, Month_Type, and{Date have already been defined, we can write{{@$^X : array(Integer range -10 .. -1, Rainbow_Color range Orange .. Blue,`{@.^Month_Type range Feb .. Jun) of Date;`{{Here the first subscript is of type Integer and has 10 possible values, the{second subscript is of type Rainbow_Color and has four possible values, and the{third subscript has type Month_Type with five possible values.  Thus we have{a three-dimensional array of 10 * 4 * 5 = 200 Dates.  One element of the array{might be^X(-5, Green, Apr)`; one field of that element might be{%X(-5, Green, Apr).Year`.  The array in this example probably has no use, other{than demonstrating that multiple subscripts need not have the same type.{{If one subscript of a multidimensional array type is constrained, they must all{be constrained.  We can't write{{@$type Rectangle is array(1 .. 5, Integer range <>) of Float;  -- illegal{}b[ 308B306]Multidimensional arrays are initialized or assigned with^nested aggregates`.  We{can create a two-dimensional array of Floats, initializing all 50 elements to{1.0, with^Mat : array(0 .. 9, 1 .. 5) of Float := (others => (others => 1.0));`.{{Here X is a 10-by-10 array of Integers.  All elements are 0, except X(4, 5),{which is 1.  We qualify the aggregate because^others~follows named notation:{{@%^type Square10 is array (1 .. 10, 1 .. 10) of Integer;`{@%^X : Square10 := Square10'(@%4@%=>@#(5 => 1, others => 0),`{@B^others  =>@'(others => 0)@');`{{We initialize or assign an^array of arrays~with nested aggregates, the same as{a multidimensional array.  However, we reference a single element differently:{{ ^type Square10 is array(1 .. 10, 1 .. 10) of Integer;`{ ^type Row10@$is array(1 .. 10) of Integer;`{ ^type Mat10@$is array(1 .. 10) of ROW10;`{ ^S : Square10 := (others => (others => 0)); -- S is a two-dimensional array.`{ ^M : Mat10@$:= (others => (others => 0)); -- M is an array of arrays.`{  ...{ ^S(4, 5) := 1; -- a single element of a two-dimensional array`{ ^M(4)(5) := 1; -- a single element of an array of arrays`{}b[ 309B307]The "short circuit" forms can prevent us from using array subscripts that are{out of range.  For example, if we write{{@4A : array(1 .. 10) of Float;{@4I : Integer;{@4...{@4if^I in A'Range and then A(I) = 0.0~then{@7-----;{@7-----;  (block of code){@7-----;{@4end if;{{then we know the program won't try to evaluate^A(I)~when I is outside the range{1 to 10.{}b[ 310B308]Which one of these is^illegal`?{{{@*1.@$subtype Day_Subtype is Integer range 1 .. 31;{@0type Group is array(Day_Subtype) of Float;{@0Gr : Group;{@0...{@0Gr(3) := 0.0;{{{@*2.@$type List is array(1 .. 10) of Integer;{@0type Page is array(1 .. 20) of List;{@0Pg : Page;{@0...{@0Pg(5)(10) := 0;{{{@*3.@$type Row is array (Integer range <>) of Integer;{@0R1 : Row;{@0...{@0R1(1) := 0;{}Please press 1, 2, or 3, or B to go back.[331113122313B309]@)^3.@$type Row is array (Integer range <>) of Integer;`{@/^R1 : Row;`{@/^...`{@/^R1(1) := 0;`{{%You're right!~ The above is illegal because the range of the subscript must be{specified, either in the first line,^(Integer range 1 .. 10)`, or in the{second,^R1 : Row(1 .. 10);`, but not both.  This is the^unconstrained array`{error mentioned earlier.{}q[ 314B310Q310]@*1.@$subtype Day_Subtype is Integer range 1 .. 31;{@0type Group is array(Day_Subtype) of Float;{@0Gr : Group;{@0...{@0Gr(3) := 0.0;{{No, the above is legal.  Gr is an array of 31 elements.  The subscript ranges{from 1 to 31, and each element has type Float.  Therefore, Gr(3) has type{Float, and the assignment is legal.{}q[ 314B310Q310]@*2.@$type List is array(1 .. 10) of Integer;{@0type Page is array(1 .. 20) of List;{@0Pg : Page;{@0...{@0Pg(5)(10) := 0;{{No, the above is legal.  The elements of an array can be of any type, including{other arrays.  Here Pg has type Page, which is an array of List.  Therefore{Pg(5) has type List (which is an array of Integer), and Pg(5)(10) has type{Integer.  Thus the assignment is legal.  The notation Pg(5)(10) may seem{strange, but it's correct Ada when we have an array of arrays.{}q[ 314B310Q310]@DSTRINGS{{There's one very important array type declaration built into the Ada language.{As with types Boolean and Character, and subtypes Positive and Natural, this{definition comes with Ada and shouldn't be repeated in our programs:{{@,^type String is array(Positive range <>) of Character;`{{Thus we can declare, for example,^S : String(1 .. 5);`.  We can't simply write{%S : String;~or^S : String := "Hello";~because we can't declare unconstrained{array objects.  (We can declare^S : constant String := "Hello";~and in Ada 9X,{we may write^S : String := "Hello";~because the compiler will translate this to{%S : String(1 .. 5) := "Hello";`).  Note that String isn't a special type in Ada,{it's just an array of Characters.  Everything we learned about arrays applies{to Strings.  For example, we can assign to S using the same syntax that we use{when assigning to an array of any other type.  If we write^S : String(1 .. 5);`{we can write:{{@7^S := ('H', 'e', 'l', 'l', 'o');`{{}b[ 315B310]However, this notation is clumsy, so Ada allows us to abbreviate an array of{Character constants using the double quote.  Thus^S := "Hello";~is equivalent{to the statement above.  If a quotation mark appears inside the string, it must{be doubled.  Thus^Text_IO.Put_Line("a ""big"" man");~will display^a "big" man`.{{It may seem disappointing that Ada Strings have fixed length, and that we can't{declare a variable^S : String;`.  Later we'll learn how to define our own type{Text to get around this restriction and simulate variable-length Strings.{{Also, Ada 9X comes with several string-handling packages to simulate variable-{-length strings; see Appendix C of the Ada 9X LRM.  The name of the Ada 9X{package that provides "Unbounded-Length String Handling" is{%Ada.Strings.Unbounded`, described in section C.4.5 of the Ada 9X LRM.{}b[ 316B314]When arrays are assigned, the^lengths~must be the same on both sides of the^:=`,{and the^types~must be the same, but the^subscripts~needn't be the same.{For example, if we have{{@/^type Vector is array(Integer range <>) of Float;`{@/^V1 : Vector(1 .. 5);`{@/^V2 : Vector(2 .. 6) := (others => 0.0);`{{@/^S1 : String(1 .. 5);`{@/^S2 : String(2 .. 6) := (others => ' ');`{{then we can write^V1 := V2;~and^S1 := S2;~even though the subscripts are{different, because the array lengths are the same and the element types are the{same.  But we'll get a Constraint_Error if we write^S1 := "Hello there";~or{%S1 := "Hi";~or^V1 := (1.0, 2.0, 3.0);`, because these arrays have wrong lengths.{Ada won't automatically truncate Strings or pad with blanks.  Of course, it{would be easy to write our own procedure to assign Strings of different{lengths, padding or truncating as necessary.{}b[ 317B315]A^slice~of an array is a portion of an array, and is indicated with a^range~in{the subscript.  A slice is itself an array.  Some languages use the term{"substring" to refer to a slice of a String, but in Ada we can take a slice of{%any~kind of array, not just an array of Characters.  So instead of "substring,"{Ada uses the more general term "slice."  For example, if we have{{@&^A : array(1 .. 10) of Integer := (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);`{{then^A(1 .. 3)~is the array^(1, 2, 3)~and^A(6 .. 9)~is the array^(6, 7, 8, 9)`.{Similarly, if we have^S : String(1 .. 11) := "Hello there";~then^S(8 .. 11)~is{%"here"~and^S(4 .. 5)~is^"lo"`.  We can also write^S(1 .. 10) := S(2 .. 11);~and{%A(1 .. 3) := A(4 .. 6);~since the lengths are the same on both sides.{{If the value preceding^..~is greater than the value following it, we have a{%null range`.  A slice with a null range has a length of zero, and is called a{%null slice`.  In the case of a null slice, the subscript is^not~checked for{Constraint_Error.  Thus, even if N is 0 we could write^S(1 .. N);~which would{produce the null string^""`.  This is legal, even though Ada defines{"type String is array(%Positive~range <>) of Character;".  Assigning a null{slice to a null slice does no harm and generates no error; it does nothing.{Also, if^S~is a null array, then^S'Length~is 0, and^S'First~and^S'Last~don't{exist.  Using^First~or^Last~with a null array will raise a Constraint_Error.{}b[ 318B316]Beginners sometimes confuse a^Character~with a^String of length 1`.  If we{write{{@=^S : String(1 .. 10);`{@=^I : Integer := 5;`{{then^S(I)~is a Character and^S(I .. I)~is a String of length 1.  Also,^'X'~is a{Character while^"X"~is a String of length 1.  Thus we could write{{@>^S(I) := 'X';`{@>^S(I .. I) := "X";`{{but we'd be mixing types if we were to write^S(I) := "X";~or^S(I .. I) := 'X';`.{{Fortunately, Text_IO has a Put for type Character as well as a Put for type{String.  (It also has a Get for each of these types.)  Thus we can write either{%Put(S(I .. I));~or^Put(S(I));`.  However, Put_Line and Get_Line exist only for{Strings, not for Characters.{}b[ 319B317]@$1.  Hello  : String := "Hello there";{@$2.  Digit  : String(0 .. 9) := "0123456789";{@$3.  Line@#: String(1 .. 80) := (others => "*");{@$4.  Hello  : String(2 .. 6) := "Hello";{@$5.  Hello  : String(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  5 => 'o');{@$6.  Prompt : String(1 .. 3) := ">";{@$7.  Hello  : String(1 .. 5) := 'Hello';{{{Which^one~of the above is legal in Ada 83?{}Please press 1, 2, 3, 4, 5, 6, or 7, or B to go back.[4320132123223323532463257326B318]@$1.  Hello  : String := "Hello there";{@$2.  Digit  : String(0 .. 9) := "0123456789";{@$3.  Line@#: String(1 .. 80) := (others => "*");{@#^4.  Hello  : String(2 .. 6) := "Hello";`{@$5.  Hello  : String(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  5 => 'o');{@$6.  Prompt : String(1 .. 3) := ">";{@$7.  Hello  : String(1 .. 5) := 'Hello';{{{%You're right!~ Number 4 creates Hello, a String of length 5, and initializes it{to "Hello", a String of the same length.  The subscript of Hello need not start{at 1, so long as the length is 5.{{In Ada 83, number 1 attempts to create an unconstrained array.  Number 2 has a{zero subscript, while Ada defines type String for Positive subscripts.  Number{3 should have^'`*%'~instead of^"`*%"`.  Number 5 tries to set each of the first{three elements, which are Characters, to a String.  Number 6 tries to store a{String of length 1 into a String of length 3, and number 7 should have^"`Hello%"`{instead of^'`Hello%'`.{}q[ 327B319Q319]@$1.  Hello  : String := "Hello there";{@$2.  Digit  : String(0 .. 9) := "0123456789";{@$3.  Line@#: String(1 .. 80) := (others => "*");{@$4.  Hello  : String(2 .. 6) := "Hello";{@$5.  Hello  : String(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  5 => 'o');{@$6.  Prompt : String(1 .. 3) := ">";{@$7.  Hello  : String(1 .. 5) := 'Hello';{{{No, number 1 is illegal in Ada 83 because it tries to create an unconstrained{array.  (However, number 1 is legal in Ada 9X.)  In Ada 83, the fact that{%"Hello there"~has a definite length doesn't make the statement legal.  We must{constrain the String to a length of 11 by writing, for example,{%Hello  : String(1 .. 11) := "Hello there";`.  However, it^is~legal to write{{@3Hello :^constant~String := "Hello there";{}q[ 327B319Q319]@$1.  Hello  : String := "Hello there";{@$2.  Digit  : String(0 .. 9) := "0123456789";{@$3.  Line@#: String(1 .. 80) := (others => "*");{@$4.  Hello  : String(2 .. 6) := "Hello";{@$5.  Hello  : String(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  5 => 'o');{@$6.  Prompt : String(1 .. 3) := ">";{@$7.  Hello  : String(1 .. 5) := 'Hello';{{{No, number 2 is illegal because of the zero subscript.  Ada defines "type{String is array(%Positive~range <>) of Character;".  Therefore, the subscripts{must be 1 or greater.{}q[ 327B319Q319]@$1.  Hello  : String := "Hello there";{@$2.  Digit  : String(0 .. 9) := "0123456789";{@$3.  Line@#: String(1 .. 80) := (others => "*");{@$4.  Hello  : String(2 .. 6) := "Hello";{@$5.  Hello  : String(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  5 => 'o');{@$6.  Prompt : String(1 .. 3) := ">";{@$7.  Hello  : String(1 .. 5) := 'Hello';{{{No, number 3 is illegal because^"`*%"~should be^'`*%'`.  As it stands, it tries to{assign a String of length 1 to each of the elements, which are Characters.{}q[ 327B319Q319]@$1.  Hello  : String := "Hello there";{@$2.  Digit  : String(0 .. 9) := "0123456789";{@$3.  Line@#: String(1 .. 80) := (others => "*");{@$4.  Hello  : String(2 .. 6) := "Hello";{@$5.  Hello  : String(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  5 => 'o');{@$6.  Prompt : String(1 .. 3) := ">";{@$7.  Hello  : String(1 .. 5) := 'Hello';{{{No, number 5 is illegal because it tries to initialize each of the first three{elements, which are Characters, to a String of length 3.  We could, however,{have written simply^Hello : String(1 .. 5);`, and then written the following in{the executable region:{{@;^Hello(1 .. 3) := "Hel";`{@;^Hello(4) := 'l';`{@;^Hello(5) := 'o';`{}q[ 327B319Q319]@$1.  Hello  : String := "Hello there";{@$2.  Digit  : String(0 .. 9) := "0123456789";{@$3.  Line@#: String(1 .. 80) := (others => "*");{@$4.  Hello  : String(2 .. 6) := "Hello";{@$5.  Hello  : String(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  5 => 'o');{@$6.  Prompt : String(1 .. 3) := ">";{@$7.  Hello  : String(1 .. 5) := 'Hello';{{{No, number 6 is illegal because it tries to assign a String of length 1 to a{String of length 3.{}q[ 327B319Q319]@$1.  Hello  : String := "Hello there";{@$2.  Digit  : String(0 .. 9) := "0123456789";{@$3.  Line@#: String(1 .. 80) := (others => "*");{@$4.  Hello  : String(2 .. 6) := "Hello";{@$5.  Hello  : String(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  5 => 'o');{@$6.  Prompt : String(1 .. 3) := ">";{@$7.  Hello  : String(1 .. 5) := 'Hello';{{{No, number 7 is illegal because it should say^"`Hello%"~instead of^'`Hello%'`.  Ada{"tic" marks (%'`) always enclose a single Character, while double quotes (%"`){always enclose an array of Characters.{}q[ 327B319Q319]@@ARRAY OPERATORS{{The operator^&~concatenates any two arrays of the same type, including two{Strings.  It can also concatenate a single element with an array of that{element type, or two single elements into an array of length two.  For example,{every use of^&~below is legal:{{@+C, D : Character := '*';{@+S2@#: String(1 .. 2);{@+S3@#: String(1 .. 3) := (others => ' ');{@+S5@#: String(1 .. 5);{{@+type Vector is array(Integer range <>) of Float;{@+F, G : Float := 1.2;{@+V2@#: Vector(1 .. 2);{@+V3@#: Vector(1 .. 3) := (others => 0.0);{@+V5@#: Vector(1 .. 5);{@+...{@*^S2 := C & D;  S5 := S2 & S3;  S3 := C & S2;  S3 := S2 & C;`{@*^V2 := F & G;  V5 := V2 & V3;  V3 := F & V2;  V3 := V2 & F;`{}b[ 328B319]The operators^and`,^or`,^xor`, and^not`, defined for Booleans, are also defined for{one-dimensional arrays of Boolean.  They operate element by element on the{arrays.  Thus, we can simulate^sets~in Ada.  For example, if we write{{@#^type Set_Of_Chars is array(Character) of Boolean;`{@#^S1 : Set_Of_Chars := Set_Of_Chars'('*' | '#' => True, others => False);`{@#^S2 : Set_Of_Chars := Set_Of_Chars'('*' | '?' => True, others => False);`{{then^S1 or S2~is^Set_Of_Chars'('*' | '#' | '?' => True, others => False)`,{and^S1 and S2~is^Set_Of_Chars'('*' => True, others => False)`.{{The operators^=~and^/=~can compare two records or two arrays of the same type.{Records are equal if all of their corresponding fields are equal, arrays, if{all of their corresponding elements are equal.  Arrays of different lengths{are always unequal.  The four remaining relational operators can compare two{arrays of the same type.  They're compared element by element until a{difference is found.  For example, if we have{{@7^S : String(1 .. 6) := "to all";`{@7^T : String(1 .. 7) := "to Bill";`{{then^S > T~because 'a' > 'B' in Ada's definition of type Character.{}b[ 329B327]@3OUTSIDE ASSIGNMENT 3 - EXERCISE IN RECORDS{{Your third Outside Assignment is to write a function specified by{{@%type Month_Type is (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);{@%subtype Day_Subtype is Integer range 1 .. 31;{@%type Date is{@(record{@+Day@#: Day_Subtype;{@+Month : Month_Type;{@+Year  : Integer;{@(end record;{@$^function Tomorrow(Today : in Date) return Date;`{{Given any date, Tomorrow should return the following date.  Your function will{be tested only with legal dates.  As with Outside Assignment 2, a test driver{is already written; it's in^NEXTDATE.ADA`.  A listing is on page 13 of your{printed course notes, but you needn't understand the test driver.  If your{function fails any test, you'll see the test case, the answer from your{function, and the right answer.  Otherwise, you'll see "Congratulations, you{completed the assignment!"{}b[ 330B328]The definitions of Month_Type, Day_Subtype, and Date are in the test driver;{you shouldn't define them inside your function.  A dummy solution is in{%TOMORROW.DUM`; it looks like this:{{@/-- Dummy solution to Outside Assignment 3{@.^separate (Nextdate)`{@.^function Tomorrow(Today : in Date) return Date is`{@.^begin`{@2return Today;{@.^end Tomorrow;`{{Again, you'll probably want to remove or change the comment line, and you{shouldn't change the lines^highlighted~above.  You may, but don't have to,{include^Answer : Date;~in the declarative region and make^return Answer;~the{last statement before^end Tomorrow;`.{{Normally, years divisible by 4 are leap years.  But if a year is divisible by{100, it must also be divisible by 400 to be a leap year.  Thus, 2000 is a leap{year, but 1900 and 2100 are not.  Note that^Today.Year~is divisible by 4 if and{only if^Today.Year mod 4 = 0`.  You may assume that^Today.Year~will always be{between 1583 and 3999, because outside this range the calendar gets more{complicated.{}b[ 331B329]The steps to follow for Outside Assignment 3 are very similar to those of{Outside Assignment 2.  They're in your printed course notes on page 14:{{1.  Compile the test driver NEXTDATE.ADA.  Also, make a copy of the dummy{@$solution by typing^COPY TOMORROW.DUM TOMORROW.ADA`.  You need do this step{@$only once.{{2.  Edit TOMORROW.ADA to become your real solution.  You may skip this step the{@$first time through, to see error messages from the test driver.{{3.  Compile TOMORROW.ADA.  If the compiler finds errors, go back to step 2.{{4.  Link with the name of the main program Nextdate.  Then execute.  If the{@$test driver displays error messages, go back to step 2.{{5.  When the message "Congratulations, you completed the assignment!" is{@$displayed, you'll have a chance to compare your solution with ours.{}b[ 332B330]There are many ways to solve this problem.  In our solution we declared an{array of Day_Subtype with subscripts of type Month_Type.  Some students use a{%case~construct on Today.Month; some use an^if~block with^elsif`s.{{This assignment should be a simple exercise in records.  Our solution fits on{one screen.  If your solution starts to get long and difficult, you should{think the problem through again.  Don't try to save the computer a few{microseconds; computers are supposed to save people time.  Instead, minimize{the^complexity~of the program to save yourself programming effort!{{Remember that an entire record can be assigned in one statement.  Also, try to{calculate the number of days in the month and^then~test for end of month and{end of year in only one place.  This is better than having several blocks of{code testing for end of month and end of year in three or four different places{in your program.  One last hint: remember that Month_Type'Succ(Today.Month){will raise a Constraint_Error if Today.Month is Dec.{{Please type X to exit^ADA-TUTR~temporarily, and try Outside Assignment 3.  Work{at your own pace; there's no deadline.  Good luck!{}Please type X to exit, a space to go on, or B to go back.[ 333B331]@-^Congratulations on Completing Outside Assignment 3!`{{-- Our solution to Outside Assignment 3 (in TOMORROW.ANS):{separate (Nextdate){function Tomorrow(Today : in Date) return Date is{@#Length : array(Month_Type) of Day_Subtype :={@>(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);{@#Answer : Date;{begin{@#if Today.Year mod 4 = 0 and{@7(Today.Year mod 100 /= 0 or Today.Year mod 400 = 0) then{@&Length(Feb) := 29;{@#end if;{@#if Today.Day /= Length(Today.Month) then@0-- Not end of month.{@&Answer := (Today.Day + 1, Today.Month, Today.Year);{@#elsif Today.Month /= Dec then@*-- End of month, but not end of year.{@&Answer := (1, Month_Type'Succ(Today.Month), Today.Year);{@#else@Y-- End of year.{@&Answer := (1, Jan, Today.Year + 1);{@#end if;{@#return Answer;{end Tomorrow;{}b[ 334B332]In our solution, the first^if~statement checks for leap year.  No^else~is{needed because the locally declared array^Length~is re-initialized every time{the function is called.  After this^if~statement, the number of days in the{month is in^Length(Today.Month)`, and it's easy to test for end of month and end{of year - in only one place in the program.{{We could have written^Month_Type'Last~instead of^Dec`, and^Month_Type'First`{instead of^Jan`.  We could even have used^Day_Subtype'First`.  But the author{reasoned that if our calendar ever changes, the entire program will probably{have to be rewritten anyway!  The program seems a little easier to read when we{use the names^Dec~and^Jan~and the number^1~directly.{{Your solution might be entirely different from ours.  If the test driver said{"Congratulations, you completed the assignment!" you may consider your solution{correct.  Let's go on to discuss recursion.{}b[ 335B333]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@9^>  RECURSION AND ASSIGNMENT 4`{{@#The Format of an Ada Program@-Subprograms and Packages{{@#Generic Instantiation and@0Access Types, User Defined Types,{@&Assignment 1@=and Derived Types{{@#Simple Declarations and Simple@+Exceptions, Text_IO, and{@&Attributes@?Assignment 5{{@#Operators, Control Constructs, and@'Generics, Tasking, and Assignment 6{@&Assignment 2{@LMore Records and Types{@#Records, Arrays, and Assignment 3{@LAdvanced Topics{}b[ 336B334]@CRECURSION{{Ada procedures and functions may call themselves, directly or indirectly.  This{process is called^recursion`.  While recursion often uses a little extra memory{and execution time, for certain types of problems it pays large dividends in{program simplicity.  That's a very worthwhile exchange!{{For example, let's write a function to compute the factorial of a positive{integer.  The factorial of an integer is the product of all the integers from{that number down to one.  Thus, Factorial(5) = 5 * 4 * 3 * 2 * 1 = 120.{Although we could easily write this function with a^for~loop, we'll use{recursion instead.  Note that if N = 1, then Factorial(N) = 1; otherwise,{Factorial(N) = N * Factorial(N - 1).{{@-function Factorial(N : in Positive) return Positive is{@0Answer : Positive := 1;{@-begin{@0if N > 1 then{@3Answer := N * Factorial(N - 1);{@0end if;{@0return Answer;{@-end Factorial;{}b[ 337B335]@-function Factorial(N : in Positive) return Positive is{@0Answer : Positive := 1;{@-begin{@0if N > 1 then{@2^Answer := N * Factorial(N - 1);`{@0end if;{@0return Answer;{@-end Factorial;{{The highlighted line shows where this function calls itself.  Recursive{subprograms always call themselves^conditionally`; otherwise the program would{run out of memory, no matter how large the machine.  Here the recursive call is{inside an^if~block.{{Note that Answer is initialized to 1.  If the function is called with N = 1,{the^if~statement is False, Answer isn't modified, and^1~is returned as the{value of the function.  If the function is called with N = 2, the^if~statement{is True, and the highlighted line is executed.  The machine starts to compute{the expression as 2 * ..., and then Factorial is called with N = 1.  It's as if{the machine made another copy of the code for Factorial and called that.{Actually there's only one copy of the code, but the machine maintains multiple{%pointers~to it.{}b[ 338B336]@-function Factorial(N : in Positive) return Positive is{@0Answer : Positive := 1;{@-begin{@0if N > 1 then{@2^Answer := N * Factorial(N - 1);`{@0end if;{@0return Answer;{@-end Factorial;{{When the recursive call is made, the system allocates additional memory for new{versions of any local variables like Answer.  Also, the parameters like N are{separate for each recursive call.{{Suppose the main program calls Factorial with N = 2.  Then, in computing the{expression, Factorial calls itself with N = 1.  In this second call, a new{local variable Answer is created, separate from the one in the first call.{Also, parameter N is 1 in the second call, but 2 in the first call.  In the{second call, the^if~statement is False, and 1 is returned.  In the first call,{the calculation of the expression is completed, using the value 1 returned by{the second call.  Thus, Answer becomes 2 * 1 = 2, and the first call returns{the answer 2 to the main program.{}b[ 339B337]@-function Factorial(N : in Positive) return Positive is{@0Answer : Positive := 1;{@-begin{@0if N > 1 then{@2^Answer := N * Factorial(N - 1);`{@0end if;{@0return Answer;{@-end Factorial;{{If the main program calls Factorial with N = 3, the function starts to compute{the expression as Answer := 3 * ..., and calls Factorial with N = 2.  In this{second call, the function starts to compute Answer := 2 * ..., and calls{Factorial with N = 1.  In this third call, the^if~statement is False, and the{answer 1 is returned to the second call.  The second call finishes the{computation of the expression Answer := 2 * 1, and returns the answer 2 to the{first call.  Finally, the first call finishes computing the expression with{Answer := 3 * 2, and returns the answer 6 to the main program.{{This simple function wouldn't have been complicated even without recursion.  In{a moment we'll discuss the Tower of Hanoi problem.  The recursive solution is{very simple, but a solution without recursion would be very complicated indeed.{}b[ 340B338]In this question, function A calls B, and B conditionally calls A.  The{specification of function B is given early so that A can call it.{{@1function B (I : in Integer) return Integer;{{@1function A (I : in Integer) return Integer is{@1begin{@4return B(I - 1) + 1;{@1end A;{{@1function B (I : in Integer) return Integer is{@4Ans : Integer := 0;{@1begin{@4if I > 0 then{@7Ans := A(I);{@4end if;{@4return Ans;{@1end B;{{If the main program calls function A with a parameter equal to 2, what value{will A return:  0, 1, 2, or 3?  You may need pencil and paper to figure this{one out.{}Please press 0, 1, 2, or 3, or B to go back.[2341034213423342B339]@1function B (I : in Integer) return Integer;{{@1function A (I : in Integer) return Integer is{@1begin{@4return B(I - 1) + 1;{@1end A;{{@1function B (I : in Integer) return Integer is{@4Ans : Integer := 0;{@1begin{@4if I > 0 then{@7Ans := A(I);{@4end if;{@4return Ans;{@1end B;{{%You're right!~ When the main program calls A(2), A starts to evaluate{B(1) + 1.  The^if~statement in B is True, so B simply calls A(1).  The call{A(1) starts to evaluate B(0) + 1.  The^if~statement in this call to B is False,{so B(0) simply returns 0, and the call A(1) returns 0 + 1 = 1.  The call B(1){returns the same answer, so the call A(2) returns 1 + 1 = 2.{}q[ 343B340Q340]@1function B (I : in Integer) return Integer;{{@1function A (I : in Integer) return Integer is{@1begin{@4return B(I - 1) + 1;{@1end A;{{@1function B (I : in Integer) return Integer is{@4Ans : Integer := 0;{@1begin{@4if I > 0 then{@7Ans := A(I);{@4end if;{@4return Ans;{@1end B;{{No, when the main program calls A(2), A starts to evaluate B(1) + 1.  The^if`{statement in B is True, so B simply calls A(1).  The call A(1) starts to{evaluate B(0) + 1.  The^if~statement in this call to B is False, so B(0) simply{returns 0, and the call A(1) returns 0 + 1 = 1.  The call B(1) returns the same{answer, so the call A(2) returns 1 + 1 = 2.{}q[ 343B340Q340]@;THE TOWER OF HANOI PROBLEM{{The "Tower of Hanoi" is a solitaire puzzle that was named when Hanoi was the{capital of a free country: French Indochina.  There are three pegs labeled A,{B, and C; one of them has a tower of N doughnut-shaped disks of decreasing{size, like this:{{@/|@7|@7|{@/|@7|@7|{@.=|=@6|@7|{@-==|==@5|@7|{@,===|===@4|@7|{@+====|====@3|@7|{@*=====|=====@2|@7|{@'-----------------@'-----------------@'-----------------{@/A@7B@7C{{The object is to move the entire tower from one peg to another, say, from A to{B.  Only one disk may be moved at a time, and a larger disk may never be placed{on top of a smaller one.  The shortest solution to the puzzle with N disks{requires 2**N - 1 moves.{}b[ 344B340]For example, we can move five disks from A to B with the following 31 moves:{(Read them from left to right, not in columns.){{A to B,  A to C,  B to C,  A to B,  C to A,  C to B,  A to B,  A to C,  B to C,{B to A,  C to A,  B to C,  A to B,  A to C,  B to C,  A to B,  C to A,  C to B,{A to B,  C to A,  B to C,  B to A,  C to A,  C to B,  A to B,  A to C,  B to C,{A to B,  C to A,  C to B,  A to B.{{@/|@7|@7|{@/|@7|@7|{@/|@7|@7|{@/|@7|@7|{@.=|=@6|@7|{@+====|====@3|@7|{@*=====|=====@/===|===@2==|=={@'-----------------@'-----------------@'-----------------{@/A@7B@7C{@4(The Puzzle After the First Five Moves){{Writing a program to display this series of moves would be very complicated{without recursion.  Let's develop a recursive solution; we'll see that the{resulting Ada program is surprisingly simple!{}b[ 345B343]When we developed a recursive solution for the Factorial function:{{@1if N = 1,  Factorial(N) = 1{@1otherwise, Factorial(N) = N * Factorial(N - 1){{we expressed Factorial(N) in terms of Factorial(N - 1), and gave the trivial{solution for N = 1.  The Ada program was easily written from the above.{{For the Tower of Hanoi problem, let's develop a solution for N disks in terms{of a solution for N - 1 disks.  Suppose we want to move five disks from A to B,{using C as a spare peg.  We first move^four~disks from A to^C`, then move one{disk from A to B, and finally move four disks from C to B.  In general, to move{N disks from a source peg to a destination peg, we first move N - 1 disks from{the source to the spare, then move one disk from the source to the destination,{and finally move N - 1 disks from the spare to the destination.{{To move the^one~disk from the source to the destination, our program will{simply display the move.  To move N - 1 disks, the program will call itself.{The solution for zero disks is trivial indeed: the program will do nothing!{{The following program is extremely simple: three executable statements inside{an^if~block.  Yet it can display a very complicated series of moves!{}b[ 346B344]@&^with Text_IO; use Text_IO;`{@&^procedure Hanoi(N : in Natural; From, To, Spare : in Character) is`{@&^begin`{@)^if N > 0 then`{@,^Hanoi(N - 1, From, Spare, To);`{@,^Put_Line(From & " to " & To);`{@,^Hanoi(N - 1, Spare, To, From);`{@)^end if;`{@&^end Hanoi;`{{To move five disks from A to B, using C as a spare, we would call{%Hanoi(5, 'A', 'B', 'C');~and the program would display the 31 moves.{{Note that when Hanoi is called with N = 0, it does nothing.  When called with{N = 1, the^if~statement is true, and the three lines within the^if~block are{executed.  But the first and third lines do nothing, because they call Hanoi{with N = 0.  The second line displays, for example,^A to B`.{{When called with a larger value of N, the first line within the^if~block moves{N - 1 disks from the source to the spare peg.  The second line displays the{move of one disk from the source to the destination, and the third line moves{N - 1 disks from the spare peg to the destination.{}b[ 347B345]Most implementations of Ada won't allow Hanoi to be a main program, because it{has parameters.  A short main program to call Hanoi is shown here.  A slightly{longer program could get N and the names of the three pegs from the user.  In{this example, procedure Demo^with`s a previously compiled~procedure~rather than{a~package`.{{@9^with Hanoi;`{@9^procedure Demo is`{@9^begin`{@<^Hanoi(5, 'A', 'B', 'C');`{@9^end Demo;`{{In summary, our first example of recursion, Factorial, was very simple.{However, that program would have been simple even without recursion.  Our{second example, Hanoi, also was very simple, but the program would have been{quite complicated without recursion.{{Our fourth Outside Assignment will be to write a Fibonacci function Fib, using{recursion.  As with Factorial, this function would be easy to write even{without recursion.  However, as an exercise we'll write it using recursion.{}b[ 348B346]@2OUTSIDE ASSIGNMENT 4 - EXERCISE IN RECURSION{{Your fourth Outside Assignment is to write, using recursion, a function{specified by{{@0^function Fib(N : in Positive) return Positive;`{{Fibonacci was a mathematician in the Middle Ages.  The so-called^Fibonacci{Series~is a series of integers.  Each number in the series is the sum of the{two previous numbers.  The first two Fibonacci numbers are 1.{{@%N:@$1  2  3  4  5  6@#7@#8@#9  10  11@#12@#13@#14@#15@#16 ...{@#Fib(N): 1  1  2  3  5  8  13  21  34  55  89  144  233  377  610  987 ...{{Note that if N = 1 or N = 2, then Fib(N) = 1; otherwise,{Fib(N) = Fib(N - 1) + Fib(N - 2).  Writing this function in Ada will be an easy{and short assignment.  A test driver is provided in^FIBTEST.ADA`; a listing is{on page 15 of your printed course notes.  As before, if all tests are passed,{it displays "Congratulations, you completed the assignment!"  If there's an{error, it displays the test case, the answer from your function, and the right{answer.{}b[ 349B347]A dummy solution is in^FIB.DUM`.  As before, you shouldn't change the lines{%highlighted~here:{{@0-- Dummy solution to Outside Assignment 4{@/^separate (Fibtest)`{@/^function Fib(N : in Positive) return Positive is`{@/^begin`{@3return 4;{@/^end Fib;`{{{The steps to follow for Outside Assignment 4 are similar to those of the last{two Outside Assignments.  They're in your printed course notes on page 16:{}b[ 350B348]1.  Compile the test driver FIBTEST.ADA.  Also, make a copy of the dummy{@$solution by typing^COPY FIB.DUM FIB.ADA`.  You need do this step only once.{{2.  Edit FIB.ADA to become your real solution.  You may skip this step the{@$first time through, to see error messages from the test driver.{{3.  Compile FIB.ADA.  If the compiler finds errors, go back to step 2.{{4.  Link with the name of the main program Fibtest.  Then execute.  If the test{@$driver displays error messages, go back to step 2.{{5.  When the message "Congratulations, you completed the assignment!" is{@$displayed, you'll have a chance to compare your solution with ours.{{{Please type X to exit^ADA-TUTR~temporarily, and try Outside Assignment 4.  Work{at your own pace; there's no deadline.  Good luck!{}Please type X to exit, a space to go on, or B to go back.[ 351B349]@-^Congratulations on Completing Outside Assignment 4!`{{@--- Our solution to Outside Assignment 4 (in FIB.ANS):{@-separate (Fibtest){@-function Fib(N : in Positive) return Positive is{@0Answer : Positive := 1;{@-begin{@0if N > 2 then{@3Answer := Fib(N - 1) + Fib(N - 2);{@0end if;{@0return Answer;{@-end Fib;{{Your solution is probably quite similar to ours.  Perhaps you used^else~and{didn't initialize Answer in the declarative region.  Perhaps you had some other{minor variation.  Our solution is probably no "better" than yours, if the test{driver said, "Congratulations, you completed the assignment!"{{Was this assignment^too~easy?  We promise that Outside Assignment 5 will be{much more challenging!  But first we need to discuss procedures and functions{in more detail, as well as packages and information hiding, access types, and{exceptions.{}b[ 352B350]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Recursion and Assignment 4{{@#The Format of an Ada Program@)^>  SUBPROGRAMS AND PACKAGES`{{@#Generic Instantiation and@0Access Types, User Defined Types,{@&Assignment 1@=and Derived Types{{@#Simple Declarations and Simple@+Exceptions, Text_IO, and{@&Attributes@?Assignment 5{{@#Operators, Control Constructs, and@'Generics, Tasking, and Assignment 6{@&Assignment 2{@LMore Records and Types{@#Records, Arrays, and Assignment 3{@LAdvanced Topics{}b[ 353B351]@<PROCEDURES AND FUNCTIONS{{When we compiled procedures Hello and Add into the library, we made it possible{for other units to^with~them and call them.  (We don't^use~procedures and{functions, because dot notation doesn't apply to them.)  We can also compile{just a^specification`, supplying the body later.  For example, we could compile{{@(^function Upper_Case(S : in String) return String;`{{and then compile the calling program.  When we later write the body, it must{agree with the specification:{{@(^function Upper_Case(S : in String) return String is`{@,Answer : String(S'Range) := S;{@)begin{@,for I in S'Range loop{@/if S(I) in 'a' .. 'z' then{@2Answer(I) := Character'Val(Character'Pos(S(I)) - 32);{@/end if;{@,end loop;{@,return Answer;{@)end Upper_Case;{}b[ 354B352]Functions and procedures may also be declared locally.  In Ada 83, such{declarations must follow any simple declarations like^S : String(1 .. 5);`.{{@'with Text_IO; use Text_IO;{@'procedure Greeting is{@*S : String(1 .. 5) := "Hello";{@)^function Upper_Case(S : in String) return String is`{@,^Answer : String(S'Range) := S;`{@)^begin`{@,^for I in S'Range loop`{@/^if S(I) in 'a' .. 'z' then`{@2^Answer(I) := Character'Val(Character'Pos(S(I)) - 32);`{@/^end if;`{@,^end loop;`{@+^return Answer;`{@)^end Upper_Case;`{@'begin{@*Put_Line(Upper_Case(S));{@'end Greeting;{{As we've seen, we can declare local functions and procedures to be^separate`.{These subprograms can in turn declare^separate~subprograms, to any depth:{}b[ 355B353]@2procedure Main is{@5function A return Float is separate;{@2begin{@5...{@2end Main;{{@1^separate (Main)`{@2function A return Float is{@5procedure B is separate;{@2begin{@5...{@2end A;{{@1^separate (Main.A)`{@2procedure B is{@5procedure C(I : in Integer) is separate;{@2begin{@5...{@2end B;{{@1^separate (Main.A.B)`{@2procedure C(I : in Integer) is ... (etc.){}b[ 356B354]However,^is separate~may be used only at the outermost level.  The example{below is legal as it stands, but we may not make procedure B separate unless we{also make function A separate, thus bringing function A to the outermost level:{{@9procedure Main is{@<F : Float;{@<function A return Float is{@?Answer : Float;{@?procedure B is{@?begin{@B...{@?end B;{@<begin{@?...{@?return Answer;{@<end A;{@9begin{@<...{@9end Main;{{A program that begins^separate (`...%)~must be compiled after the program that{says^is separate`, because a separate subprogram depends on its "parent."{}b[ 357B355]A procedure or function specification gives the name, mode, and type of each{parameter.  A function specification also gives the type of the result.  The{mode can be^in`,^out`, or^in out`.  The subprogram may read from, but not write{to,^in~parameters, and it may write to, but not read from,^out~parameters.  (In{Ada 9X, it may read^out~parameters.)  If the mode is omitted, it's assumed to{be^in`.  Thus, these two lines have the same effect:{{@'^procedure Hanoi(N : in Natural; From, To, Spare : in Character);`{@'^procedure Hanoi(N : Natural;@$From, To, Spare : Character);`{{The parameters of a^function~must always be of mode^in`, never^out~or^in out`.{{Note that when several parameters have the same mode and type, they can be{placed in one list, separated by commas.  The lists themselves are separated by{semicolons.  The two specifications above are equivalent to:{{%procedure Hanoi(N : Natural; From: Character; To: Character; Spare: Character);`{{In any event, the parameters in a^call~to a procedure or function are always{separated by^commas`:{{@;^Hanoi(5, 'A', 'B', 'C');`{}b[ 358B356]@#1.  procedure P(A; B; C : in Integer);{{@#2.  procedure P(A, B, C : Integer; D, E : in out Float) return Character;{{@#3.  function  F(A, B, C : Integer; D, E : in out Float) return Character;{{@#4.  procedure P(A, B, C : Integer; D, E : in out Float);{{{Which one of the above is^legal`?{}Please press 1, 2, 3, or 4, or B to go back.[4359136023613362B357]@#1.  procedure P(A; B; C : in Integer);{{@#2.  procedure P(A, B, C : Integer; D, E : in out Float) return Character;{{@#3.  function  F(A, B, C : Integer; D, E : in out Float) return Character;{{  ^4.  procedure P(A, B, C : Integer; D, E : in out Float);`{{%You're right!~ In a subprogram specification, the items of a list are separated{by commas, and the lists are separated by semicolons.  In a list, the mode may{be omitted; it's assumed to be^in`.{{In number 1, the items should be separated by commas.  Number 2 has a^return`{clause in a^procedure~specification, and number 3 has a mode other than^in~in a{%function~specification.{}q[ 363B358Q358]@#1.  procedure P(A; B; C : in Integer);{{@#2.  procedure P(A, B, C : Integer; D, E : in out Float) return Character;{{@#3.  function  F(A, B, C : Integer; D, E : in out Float) return Character;{{@#4.  procedure P(A, B, C : Integer; D, E : in out Float);{{No, in number 1 the items should be separated by commas, not semicolons.  In a{subprogram specification, the items in a list are separated by commas, and the{lists are separated by semicolons.  Here a "list" means a collection of{parameters sharing the same mode and type (%in Integer`).{}q[ 363B358Q358]@#1.  procedure P(A; B; C : in Integer);{{@#2.  procedure P(A, B, C : Integer; D, E : in out Float) return Character;{{@#3.  function  F(A, B, C : Integer; D, E : in out Float) return Character;{{@#4.  procedure P(A, B, C : Integer; D, E : in out Float);{{No, number 2 is illegal because a^return~clause applies only to a function{specification, not a procedure specification.{}q[ 363B358Q358]@#1.  procedure P(A; B; C : in Integer);{{@#2.  procedure P(A, B, C : Integer; D, E : in out Float) return Character;{{@#3.  function  F(A, B, C : Integer; D, E : in out Float) return Character;{{@#4.  procedure P(A, B, C : Integer; D, E : in out Float);{{No, number 3 is illegal because all parameters of a function must have mode^in`.{}q[ 363B358Q358]Recall that type conversion from Float to Integer in Ada rounds to the nearest{integer.  (The Ada 83 standard doesn't specify which way rounding occurs when{the fractional part is exactly 0.5; the Ada 9X standard specifies rounding away{from zero in such cases.)  This function Floor computes the largest integer{less than or equal to a given Float, always rounding toward negative infinity:{{@1function Floor(X : in Float) return Integer is{@4Answer : Integer := Integer(X);{@1begin{@4if Float(Answer) > X then{@7Answer := Answer - 1;{@4end if;{@4return Answer;{@1end Floor;{}b[ 364B358]Similarly, this function Truncate converts from Float to Integer, always{truncating toward zero:{{@/function Truncate(X : in Float) return Integer is{@2Answer : Integer := Integer(X);{@/begin{@2if Answer > 0 and Float(Answer) > X then{@5Answer := Answer - 1;{@2elsif Answer < 0 and Float(Answer) < X then{@5Answer := Answer + 1;{@2end if;{@2return Answer;{@/end Truncate;{}b[ 365B363]@?DEFAULT PARAMETERS{{The^in~parameters of a subprogram specification may be given default values.{Suppose, for example, that the package Integer_IO is instantiated for the type{Integer.  Here's a simplified version of the specification for the procedure{Put (the actual specification can be found in section 14.3.10 of the LRM):{{@3^procedure Put(Item  : in Integer;`{@A^Width : in Integer := 6;`{@A^Base  : in Integer := 10);`{{This means that, in calls to Put, the Width and Base parameters are optional.{If Width is omitted, it's assumed to be 6, and if Base is omitted, it's assumed{to be 10.  If either of these parameters is given in the call, the default{value is overridden.  (The default value for Width is shown here as 6.{Actually, it depends on the implementation of Ada.  Of course, the default{value for Base is always 10.){{Default parameters let us make our Ada subprograms both^flexible~and^easy to{use`.  In other languages, we'd often have to choose between these two{qualities.  For example, suppose J is an integer.  Here are some calls to Put:{}b[ 366B364]@4procedure Put(Item  : in Integer;{@BWidth : in Integer := 11;{@BBase  : in Integer := 10);{{@3^Put(J);`{@3^Put(J, Width => 4);`{@3^Put(J, Base => 16);`{@3^Put(J, Base => 16, Width => 4);`{{The first parameter in each call could have been given as^Item => J`, but{everyone remembers that the first parameter of Put is the item, so named{notation seems unnecessary for this parameter.  However, Width and Base are{used less frequently.  We used named notation for these parameters so the{reader of our code wouldn't have to remember which parameter comes second and{which comes third.  Note that if we omit the second parameter and specify the{third, we^must~use named notation for the third parameter; we're not allowed to{write Put(J, ,16); as in some languages.{{If we were writing Put in another language, we'd have to choose either making{the user specify the width and the base in every call (giving flexibility), or{writing Put with only one parameter (giving ease of use).  In Ada, default{parameters give us both flexibility and ease of use!{}b[ 367B365]Text_IO.New_Line has one parameter, Spacing, defaulted to 1.  Thus, we can call{%New_Line;~to get one CR-LF, or, for example,^New_Line(3);~to get three.{{Default values may also be given in record definitions.  If we write{{@%type Month_Type is (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);{@%subtype Day_Subtype is Integer range 1 .. 31;{@%type Date is{@(record{@+Day@#: Day_Subtype;{@+Month : Month_Type;{@+Year  : Integer^:= 1776`;{@(end record;{@%USA : Date;{{then^USA.Year~is set to 1776 when the line declaring^USA~is elaborated.  Every{time an object of type Date is declared, its Year field is set to 1776.{However, there's a difference between default values in records and default{parameters in subprograms.  We can't write USA := (4, Jul); all three fields of{the record must be specified.{}b[ 368B366]@4procedure Put(Item  : in Integer;{@BWidth : in Integer := 11;{@BBase  : in Integer := 10);{{Which one of these is^legal`?{{@:1.  Put(Item => 23, 5, 10);{{@:2.  Put(23, 5);{{@:3.  Put(23; 5; 10);{}Please press 1, 2, or 3, or B to go back.[236913703371B367]@4procedure Put(Item  : in Integer;{@BWidth : in Integer := 11;{@BBase  : in Integer := 10);{{{@:1.  Put(Item => 23, 5, 10);{{@9^2.  Put(23, 5);`{{@:3.  Put(23; 5; 10);{{{%You're right!~ The third parameter may be omitted because it has a default{value.  In number 1, positional notation follows named, which isn't allowed,{and in number 3, the separators should be commas.{}q[ 372B368Q368]@4procedure Put(Item  : in Integer;{@BWidth : in Integer := 11;{@BBase  : in Integer := 10);{{{@:1.  Put(Item => 23, 5, 10);{{@:2.  Put(23, 5);{{@:3.  Put(23; 5; 10);{{{No, number 1 is illegal because positional notation may not follow named.{}q[ 372B368Q368]@4procedure Put(Item  : in Integer;{@BWidth : in Integer := 11;{@BBase  : in Integer := 10);{{{@:1.  Put(Item => 23, 5, 10);{{@:2.  Put(23, 5);{{@:3.  Put(23; 5; 10);{{{No, number 3 is illegal because in a call, the parameters are always separated{with commas, not semicolons.{}q[ 372B368Q368]@DPACKAGES{{A^package~lets us group related declarations, procedures, and functions.  A{program can^with~the package and gain access to all of these.  However, as{we'll see, packages have many other advantages.  Usually library units are{packages rather than individual procedures and functions.{{By way of example, consider a very simple procedure and a very simple function:{{@)^procedure Double(Number : in Integer; Answer : out Integer);`{@)^function Twice(Number : in Integer) return Integer;`{{We could compile these individually, or we could put them in a^package~and{compile that instead.  Here's the package^specification`:{{@'^package Simple_Math is`{@+procedure Double(Number : in Integer; Answer : out Integer)%;`{@+function Twice(Number : in Integer) return Integer%;`{@'^end Simple_Math;`{{The package^body~must contain the bodies of all the procedures and functions{declared in the package specification:{}b[ 373B368]@&^package body Simple_Math is`{@*procedure Double(Number : in Integer; Answer : out Integer)^is`{@*begin{@-Answer := Number * 2;{@*end Double;{{@*function Twice(Number : in Integer) return Integer^is`{@*begin{@-return Number * 2;{@*end Twice;{@&^end Simple_Math;`{{The package body could optionally declare either or both subprograms to be{%separate`:{{ ^package body Simple_Math is`{@%procedure Double(Number : in Integer; Answer : out Integer)^is separate;`{@%function Twice(Number : in Integer) return Integer^is separate;`{ ^end Simple_Math;`{{Here's an example of a calling program that^with`s the package and makes use of{the two subprograms declared in the package specification:{}b[ 374B372]@$^with Simple_Math; use Simple_Math;`{@%procedure Package_Demo is{@(I, J : Integer := 10;{@%begin{@'^Double`(Number => I, Answer => J);  -- This line sets J to 20.{@(J :=^Twice`(I);@5-- This line also sets J to 20.{@%end Package_Demo;{{The package specification must be compiled first, but either the calling{program or the package body may be compiled second.  The calling program{depends only on the package^specification`, not the package^body`.  Similarly,{the package body depends on the package specification.  If the package body{declares any subprograms to be^separate`, these must be compiled after the{package body, because any^separate~subprogram depends on its "parent."{{A package specification that declares no subprograms (only objects, types,{etc.) doesn't need a package body.{{The main program may never be inside a package.  It must be a procedure or{function compiled directly into the library, such as HELLO or ADD.  In most{implementations of Ada, the main program can't have any parameters, and must be{a procedure rather than a function.{}b[ 375B373]A package body may optionally have initialization code, introduced by the word{%begin`.  This code is executed only once, the first time another program{elaborates the package by^with`ing it.  For example, this package uses{initialization code to initialize the array B:{{@/package P is{@2function F return Float;{@/end P;{{@/package body P is{@2A : array(1 .. 10) of Float := (others => 0.0);{@2B : array(1 .. 10, 1 .. 10) of Integer;{@2function F return Float is{@5...{@2end F;{@.^begin`{@1^for I in 1 .. 10 loop`{@4^for J in 1 .. 10 loop`{@7^B(I, J) := I*J*J;`{@4^end loop;`{@1^end loop;`{@/end P;{}b[ 376B374]Declarations made inside a package^specification~are said to be^exported~and{are available to programs outside the package that^with~the package.  However,{declarations made inside the package^body~are available only inside the{package.  The package body doesn't even have to be written before outside{programs that^with~the package.  In this example, programs outside and inside{the package may use type Answer, array A, and procedure R, but only procedures{P, Q and R may use type Question and array B.  Procedure P may be called only{by Q and R (and itself), and procedure Q is available only to R (and itself).{{@6package X is{@9type Answer is (Yes, No, Maybe);{@9A : array(1 .. 10) of Float;{@9procedure R;{@6end X;{{@6package body X is{@9type Question is (Why, Who, How);{@9B : array(1 .. 10) of Integer;{@9procedure P is separate;{@9procedure Q is separate;{@9procedure R is separate;{@6end X;{}b[ 377B375]@6package X is{@9type Answer is (Yes, No, Maybe);{@9A : array(1 .. 10) of Float;{@9procedure R;{@6end X;{{@6package body X is{@9type Question is (Why, Who, How);{@9B : array(1 .. 10) of Integer;{@9procedure P is separate;{@9procedure Q is separate;{@9procedure R is separate;{@6end X;{{True or False?  In this example, procedure P may call R.{}Please press T for true or F for false, or B to go back.[T378F379B376]@6package X is{@9type Answer is (Yes, No, Maybe);{@9A : array(1 .. 10) of Float;{@9procedure R;{@6end X;{{@6package body X is{@9type Question is (Why, Who, How);{@9B : array(1 .. 10) of Integer;{@9procedure P is separate;{@9procedure Q is separate;{@9procedure R is separate;{@6end X;{{%You're right!~ R is declared in the package specification, so any program{inside X (and any program outside X that^with`s the package) may call R.{}q[ 380B377Q377]@6package X is{@9type Answer is (Yes, No, Maybe);{@9A : array(1 .. 10) of Float;{@9procedure R;{@6end X;{{@6package body X is{@9type Question is (Why, Who, How);{@9B : array(1 .. 10) of Integer;{@9procedure P is separate;{@9procedure Q is separate;{@9procedure R is separate;{@6end X;{{True.  R is declared in the package specification, so any program inside X (and{any program outside X that^with`s the package) may call R.{}q[ 380B377Q377]@9FUNCTIONS WITH INFIX NOTATION{{@1^+@#-@#*@#/@#**@#&@#=@#<@#>@#<=@#>=`{{@4^and@#or@#xor@#abs@#not@#mod@#rem`{{Ada allows us to overload any of the above operators by enclosing the operator{in quotes following the word^function`.  For example, having defined type Date,{we may want to define what it means for one date to be "less than" another.  We{could write^function "<"(Left, Right : in Date) return Boolean;`.  Then, our{program could declare^D1, D2 : Date;~and test^D1 < D2`.  This test would call{our function "<", because^<~is used between two objects of type Date.{Similarly, we can overload "*" to give the dot product of two vectors:{{@.type Vector is array(Integer range <>) of Float;{@.V1, V2 : Vector(1 .. 100);{@.X : Float;{@-^function "*"(Left, Right : in Vector) return Float is`{@1...{@-^end "*";`{@....{@-^X := V1 * V2;  -- This calls our function "*".`{}b[ 381B377]@1^+@#-@#*@#/@#**@#&@#=@#<@#>@#<=@#>=`{{@4^and@#or@#xor@#abs@#not@#mod@#rem`{{There are some restrictions when using infix notation.  First, all of the{operators above (except^abs`,^not`,^+`, and^-`) must be used between two{expressions, and thus the function specification must have exactly two{parameters.  Traditionally, the two parameters are called Left and Right.  The{operators^abs~and^not~must have just one expression on the right, and^+~and^-`{may have one expression on the right, or come between two expressions.  These{restrictions come from the way the compiler handles operators.  For example,{the compiler can handle^X := - X;`, but it's not designed to handle^X := * X;`.{{Second, in Ada 83 the function "=" must return type Boolean, its two parameters{must be of the same type, and that type must be a limited private type, to be{discussed later.  For all the types discussed so far, function "=" is^already{defined~by Ada.  Two records are equal if all of their corresponding fields are{equal, and two arrays are equal if they have the same length and all of their{corresponding elements are equal.{}b[ 382B380]@1^+@#-@#*@#/@#**@#&@#=@#<@#>@#<=@#>=`{{@4^and@#or@#xor@#abs@#not@#mod@#rem`{{Note that in Ada 83 we can't redefine function "/=".  However, if we redefine{"=" for some limited private type, we can use^/=`.  Ada will call our function{"=" and negate the result.  For example,{{@*type Text is limited private;  -- to be discussed later{@*T1, T2 : Text;{@)^function "="(Left, Right : in Text) return Boolean is`{@-...{@)^end "=";`{@*...{@*if^T1 /= T2~then ^-- Calls our "=" and reverses the result.`{@-...{@*end if;{{Also, we can't redefine^in`,^not in`,^and then`,^or else`, or^:=`.  Technically,{these aren't operators.{}b[ 383B381]In Ada 9X, we may redefine^=~to return any type, not just Boolean.  However, if{we do redefine^=~to return type Boolean, then we have automatically also{redefined^/=~to call our^=~and reverse the result.{{If, on the other hand, we redefine^=~to return some type other than Boolean,{then^/=~is^not~automatically redefined.  However, in this case Ada 9X lets us{separately redefine^/=~if we want to, and it may return any type.{}b[ 384B382]Finally, functions using infix notation can't be compiled directly into the{library.  They must either be declared locally inside a procedure or function,{or placed inside a package.  This is done because many implementations of Ada{create files with names based on the function, procedure, or package being{compiled.  Since many of the operators are punctuation marks, they would create{file names that are illegal on most systems.{{For the same reason, two functions or procedures with the same name can't be{compiled directly into the library; on many systems that would attempt to give{the same name to two different files.  For example, the package specification{below is legal.  However, the package body can't declare both Display's{%separate`, and it can't declare either "*"^separate`.{{@+package P is{@.type Complex is ...{@.type Vector is ...{@-^procedure Display(C : in Complex);`{@-^procedure Display(V : in Vector);`{@-^function  "*"(Left, Right : in Complex) return Complex;`{@-^function  "*"(Left, Right : in Vector)  return Float;`{@+end P;{}b[ 385B383]@+package K is{@.type Complex is{@1record{@4Re, Im : Float;{@1end record;{@.type Vector is array(Integer range <>) of Float;{@.function  "+"(Left, Right : in Complex) return Complex;{@.function  "*"(Left, Right : in Complex) return Complex;{@.function  "*"(Left, Right : in Vector)  return Float;{@.function  Conjugate(C : in Complex) return Complex;{@.procedure Display(C : in Complex);{@.procedure Display(V : in Vector);{@+end K;{{The above is a package specification.  In the package body, how many{subprograms could be made^separate`:  0, 1, 2, 3, 4, 5, or 6?{}Please press 0, 1, 2, 3, 4, 5, or 6, or B to go back.[2386038713873388438853886388B384]@'package^body~K is{@*function  "+"(Left, Right : in Complex) return Complex is ...{@*function  "*"(Left, Right : in Complex) return Complex is ...{@*function  "*"(Left, Right : in Vector)  return Float is ...{@)^function  Conjugate(C : in Complex) return Complex is separate;`{@*procedure Display(C : in Complex) is ...{@)^procedure Display(V : in Vector) is separate;`{@'end K;{{@&^separate (K)`{@&^function Conjugate(C : in Complex) return Complex is`{@'...{@&^end Conjugate;`{{@&^separate (K)`{@&^procedure Display(V : in Vector) is`{@'...{@&^end Display;`{{%You're right!~ Only function Conjugate and at most one Display can be made{%separate`.  Functions using infix notation can't be made^separate`, and the name{Display is overloaded.{}q[ 389B385Q385]@+package K is{@.type Complex is{@1record{@4Re, Im : Float;{@1end record;{@.type Vector is array(Integer range <>) of Float;{@.function  "+"(Left, Right : in Complex) return Complex;{@.function  "*"(Left, Right : in Complex) return Complex;{@.function  "*"(Left, Right : in Vector)  return Float;{@.function  Conjugate(C : in Complex) return Complex;{@.procedure Display(C : in Complex);{@.procedure Display(V : in Vector);{@+end K;{{No, the function Conjugate can be made^separate`, because its name isn't{overloaded and it doesn't use infix notation.  Also, one, but not both, Display{procedures can be made^separate.`{}q[ 389B385Q385]@+package K is{@.type Complex is{@1record{@4Re, Im : Float;{@1end record;{@.type Vector is array(Integer range <>) of Float;{@.function  "+"(Left, Right : in Complex) return Complex;{@.function  "*"(Left, Right : in Complex) return Complex;{@.function  "*"(Left, Right : in Vector)  return Float;{@.function  Conjugate(C : in Complex) return Complex;{@.procedure Display(C : in Complex);{@.procedure Display(V : in Vector);{@+end K;{{No, only function Conjugate and at most one Display can be made^separate`.{Functions using infix notation can't be made^separate`, and the name Display is{overloaded.{}q[ 389B385Q385]@7INFORMATION HIDING: PRIVATE TYPES{{Information hiding has nothing to do with secrecy; it means containing certain{programming details to a package so that the parts of the program outside the{package can't depend on them.  Thus, when these details change, other parts of{the program aren't affected.{{Let's write the specification (only) for a graphics CRT controller package{without information hiding.  Then we'll improve on it by using a private type.{{The package will let us create arrays in memory representing screens.  We can{create as many of these "virtual screens" as we like, and draw dots, lines, and{boxes on them in memory.  We can also display any virtual screen.  Here's the{package specification:{}b[ 390B385]%package CRT_Controller is`{  ^type Color_Type  is (White, Black, Red, Yellow, Green, Blue);`{  ^type Screen_Type is array(0 .. 299, 0 .. 399) of Color_Type;`{  ^type Point is`{@%^record`{@(^Row@$: Integer range 0 .. 299;`{@(^Column : Integer range 0 .. 399;`{@%^end record;`{  ^procedure Display (Screen : in Screen_Type);`{  ^procedure Clear@#(Screen : in out Screen_Type; To: in Color_Type := Black);`{  ^procedure Dot@%(Screen : in out Screen_Type; Place : in Point;`{@5^Color : in Color_Type);`{  ^procedure Line@$(Screen : in out Screen_Type; From, To : in Point;`{@5^Color : in Color_Type);`{ ^ procedure Box@%(Screen : in out Screen_Type; Corner1, Corner2 : in Point;`{@5^Color : in Color_Type);{end CRT_Controller;`{{This package assumes that the resolution of the CRT is 300 vertically by 400{horizontally.  A screen is represented in memory by a two-dimensional array,{each element of which contains one of six possible colors.  Procedures to draw{other figures (circles, etc.) could have been added to the package.{}b[ 391B389]That package specification makes the calling program very clear!  For example,{{@#^with CRT_Controller; use CRT_Controller;`{@#^procedure CRT_Demo is`{@&^S1, S2 : Screen_Type;`{@#^begin`{@&^Clear(S1);`{@&^Clear(S2, To => White);`{@&^Line(S1, From => (150, 100), To => (150, 300), Color => Green);`{@&^Dot(S1, Place => (150, 200), Color => Red);`{@&^Display(S1);`{@&^Box(S2, Corner1 => (240, 100), Corner2 => (60, 300), Color => Blue);`{@&^Dot(S2, Place => (150, 200), Color => Yellow);`{@&^Display(S2);`{@#^end CRT_Demo;`{{The first executable line clears memory for screen S1 to all black, because of{the default parameter in the specification of Clear.  The next line clears S2{to all white.  The next three lines draw a line and a dot on S1 and display S1.{The program then draws a box and a dot on S2 and displays S2.  Named notation{could optionally have been used for the first parameter of each call, and for{the objects of type Point, e.g.,^(Row => 150, Column => 100)`.{}b[ 392B390]At a sacrifice in clarity (not recommended!), the calling program CRT_Demo{could draw a dot in the center of screen S1 without calling Dot.  Which of the{following statements would accomplish the same thing as{{@4Dot(S1, Place => (150, 200), Color => Red);{{{@01.  S1(150, 200) := Red;{{@02.  S1(Row => 150, Column => 200) := Red;{{@03.  Either of the above would work.{}Please press 1, 2, or 3, or B to go back.[139323943394B391]@3^Dot(S1, Place => (150, 200), Color => Red);`{{{@/^1.  S1(150, 200) := Red;`{{@02.  S1(Row => 150, Column => 200) := Red;{{@03.  Either of the above would work.{{{%You're right!~ At a sacrifice in clarity, the appropriate element of S1 can be{set directly to Red to draw a dot in the center of the screen.  Number 2 is{wrong because the names Row and Column apply to type Point, not to subscripts{of the array.{}q[ 395B392Q392]@4Dot(S1, Place => (150, 200), Color => Red);{{{@01.  S1(150, 200) := Red;{{@02.  S1(Row => 150, Column => 200) := Red;{{@03.  Either of the above would work.{{{No, the names Row and Column apply to type Point, not to subscripts of the{array.  For this reason number 2 won't compile.{}q[ 395B392Q392]Although the calling program is very clear, there's one disadvantage that can{be eliminated by using a private type: if the resolution of the screen is{changed, the calling program is affected.  For example, the two calls to Dot{are each intended to draw a dot in the center of the screen.  These calls will{have to be changed when the resolution changes, or the dot will no longer be in{the center.  Also, nothing prevents CRT_Demo from saying^S1(150, 200) := Red;`{directly, instead of calling Dot.  This is a disadvantage, because referencing{the elements of the array directly makes CRT_Demo very susceptible to changes{in the package.{{It would be better to force CRT_Demo to call our procedure Dot, and make it{impossible for CRT_Demo to use the fact the a screen is represented by a{two-dimensional array.  Then the representation of a screen can change without{affecting the correctness of CRT_Demo.{{We'll improve our package specification and calling program to make Screen_Type{a^private~type, so that its details can be used only inside the package.  Since{the screen resolution won't be available outside the package, we'll normalize{Row and Column, making them floating point numbers in the range 0.0 .. 1.0.{}b[ 396B392]Here's our improved package specification:{{package CRT_Controller is{@#type Color_Type  is (White, Black, Red, Yellow, Green, Blue);{  ^type Screen_Type is private;`{@#type Point is{@&record{@)Row@$:^Float range 0.0 .. 1.0`;{@)Column :^Float range 0.0 .. 1.0`;{@&end record;{@#procedure Display (Screen : in Screen_Type);{@#procedure Clear@#(Screen : in out Screen_Type; To: in Color_Type := Black);{@#procedure Dot@%(Screen : in out Screen_Type; Place : in Point;{@6Color : in Color_Type);{@#procedure Line@$(Screen : in out Screen_Type; From, To : in Point;{@6Color : in Color_Type);{@#procedure Box@%(Screen : in out Screen_Type; Corner1, Corner2 : in Point;{@6Color : in Color_Type);{%private`{  ^type Screen_Type is array(0 .. 299, 0 .. 399) of Color_Type;`{end CRT_Controller;{}b[ 397B395]@(package CRT_Controller is{@+...{@*^type Screen_Type is private;`{@+procedure Display (Screen : in Screen_Type);{@+procedure Clear@#(Screen : in out Screen_Type; ... );{@+...{@'^private`{@*^type Screen_Type is array(0 .. 299, 0 .. 399) of Color_Type;`{@(end CRT_Controller;{{Outside the package, there are only four things a calling program may do with{objects of a private type like Screen_Type:{{1. ^Create them:~ S1, S2 : Screen_Type;{{2. ^Assign them:~ S1 := S2;{{3. ^Test them for equality and inequality:~ if S1 = S2 ...@#if S1 /= S2 ...{{4. ^Use any procedures, functions, and infix operators provided by the package:`{@$Clear(S1);@#Display(S2);@#etc.{}b[ 398B396]@'^With objects of a private type, outside the package we may only:`{^1.  Create@%2.  Assign@%3.  Test  =  /=@%4.  Call package subprograms`{{Note that the calling program, outside the package, can no longer say{%S1(150, 200) := Red;`, because that's not one of the four things listed above.{The calling program is forced to call Dot.  The information that Screen_Type is{an array can be used by code only^inside~the package.  Of course, the^compiler`{uses this information when compiling code outside or inside the package.{That's why the definition of Screen_Type must be in the package specification,{not the body.  But the^programmer~isn't allowed to use this information outside{the package.{{%Inside~the package there are no such restrictions.  To write the bodies of the{subprograms, we'll have to use the structure of Screen_Type and write{statements similar to^S1(150, 200) := Red;`.{{Here's our calling program, revised to agree with the improved package{specification:{}b[ 399B397]@#with CRT_Controller; use CRT_Controller;{@#procedure CRT_Demo is{@&S1, S2 : Screen_Type;{@#begin{@&Clear(S1);{@&Clear(S2, To => White);{@&Line(S1, From => (%0.5`,^0.25`), To => (%0.5`,^0.75`), Color => Green);{@&Dot(S1, Place => (%0.5`,^0.5`), Color => Red);{@&Display(S1);{@&Box(S2, Corner1 => (%0.8`,^0.25`), Corner2 => (%0.2`,^0.75`), Color => Blue);{@&Dot(S2, Place => (%0.5`,^0.5`), Color => Yellow);{@&Display(S2);{@#end CRT_Demo;{{Now, if a change is made only to the private part of the package specification,{CRT_Demo won't have to be revised.  It^will~have to be recompiled, because the{Ada compiler needs the information in the private part of the package{specification.  (The linker won't link with obsolete units, but will tell us{what we must recompile.)  Also, the package body may have to be rewritten.  But{if CRT_Demo was correct before, it will remain correct without any revision!{The effects of the change are confined to the package.  Containing the effects{of changes by means of information hiding is one of Ada's greatest features.{}b[ 400B398]True or False?  If the private part of a package specification is changed, the{calling program must be recompiled before the package body is recompiled.{}Please press T for true or F for false, or B to go back.[F401T402B399]%You're right!~ The package body and the calling program both depend on the{package specification, but not on each other.  They can be compiled in either{order after the package specification is compiled.{}q[ 403B400Q400]False.  The package body and the calling program don't depend on each other,{but only on the package specification.  Thus they can be compiled in either{order after the package specification is compiled.{}q[ 403B400Q400]If a package exports a constant of a private type, the constant is declared in{the "public" part of the package specification, but it can't be assigned a{value until we get to the private part.  This is called a^deferred constant`.{For example,{{package CRT_Controller is{@#type Color_Type  is (White, Black, Red, Yellow, Green, Blue);{@#type Screen_Type is private;{  ^Flag_Of_Italy : constant Screen_Type;`{@#procedure Display (Screen : in Screen_Type);{@#...{private{@#type Screen_Type is array(0 .. 299, 0 .. 399) of Color_Type;{  ^Flag_Of_Italy : constant Screen_Type :=`{@&^(others => (0 .. 132 => Green, 133 .. 266 => White, 267 .. 399 => Red));`{end CRT_Controller;{{CRT_Demo could then say^S1 := Flag_Of_Italy;~or^Display(Flag_Of_Italy);`.{}b[ 404B400]@6TYPE TEXT AND LIMITED PRIVATE TYPES{{Earlier we remarked that Ada strings are of fixed length.  Section 7.6 of the{Ada 83 LRM suggests that we create a type Text to get around this restriction.{Instead of declaring objects to be Strings, we'll declare them to be of type{Text, which will simulate variable-length strings.  Then we'll see how this{creates a need for limited private types.{{The suggestion for type Text isn't found in section 7.6 of the Ada 9X LRM,{because Ada 9X comes with several string handling packages not found in Ada 83.{Some of these are{{Fixed-Length String Handling:@&Ada.Strings.Fixed{Bounded-Length String Handling:@$Ada.Strings.Bounded{Unbounded-Length String Handling:  Ada.Strings.Unbounded{{All of these packages are described in Appendix C of the Ada 9X LRM.{{However, let us return to the problem of simulating variable-length strings{with the type Text, as suggested in section 7.6 of the Ada 83 LRM.{}b[ 405B403]The package specification in section 7.6 of the Ada 83 LRM makes use of{discriminated records.  Since we haven't yet covered that topic, we'll give a{simplified presentation here.  Let's declare{{@3^type Text is`{@6^record`{@9^Len : Integer range 0 .. 80 := 0;`{@9^Val : String(1 .. 80);`{@6^end record;`{{Any appropriate maximum length may be used in place of 80.  It isn't necessary{to initialize the Val field to all blanks, because the Len field keeps track of{how much of the Val field is significant.  The Len field is given a default{value of 0, so that objects of type Text will be initialized to zero length.{}b[ 406B404]@3^type Text is`{@6^record`{@9^Len : Integer range 0 .. 80 := 0;`{@9^Val : String(1 .. 80);`{@6^end record;`{{For example, we could declare^T1 : Text;`.  We could then set^T1.Len := 5;~and{%T1.Val(1 .. 5) := "Hello";`.  The fact that the last 75 characters of T1.Val{might contain garbage is of no consequence, because T1.Len tells our program{to consider only the first 5 characters of T1.Val.  Since T1.Len is a variable,{we've simulated variable-length strings.{{A minor disadvantage is that, for each object of type Text, we reserve enough{memory for the longest possible length (80 in this example).  Discriminated{records, to be covered in the section on More Records and Types, can overcome{this disadvantage.{}b[ 407B405]Type Text will be much easier to use if we write some subprograms.  First, we{need to convert between types Text and String.  Conversion in both directions{is very simple:{{@2^function Str(T : in Text) return String is`{@2^begin`{@5^return T.Val(1 .. T.Len);`{@2^end Str;`{{@2^function Txt(S : in String) return Text is`{@5^Answer : Text;`{@2^begin`{@5^Answer.Len := S'Length;`{@5^Answer.Val(1 .. Answer.Len) := S;`{@5^return Answer;`{@2^end Txt;`{{Now we can write, for example,^T1 : Text := Txt("Hello");~and we don't even{have to count the characters of "Hello".  Later, the program might execute{%T1 := Txt("Type Text is very convenient.");~showing that T1 simulates a{variable-length string.  If we^with~and^use~Text_IO in our program, we can{write^Put_Line(Str(T1));`.{}b[ 408B406]It would be convenient to overload the^&~operator to concatenate two Texts, or{a Text with a String.  We can also overload four of the relational operators:{{@%^function "&"  (Left, Right : in Text)@/return Text;`{@%^function "&"  (Left : in Text;@#Right : in String) return Text;`{@%^function "&"  (Left : in String; Right : in Text)@#return Text;`{@%^function "<"  (Left, Right : in Text)@/return Boolean;`{@%^function ">"  (Left, Right : in Text)@/return Boolean;`{@%^function "<=" (Left, Right : in Text)@/return Boolean;`{@%^function ">=" (Left, Right : in Text)@/return Boolean;`{{The bodies of these subprograms are very simple!  For example:{{@,^function "&"(Left, Right : in Text) return Text is`{@,^begin`{@/^return Txt(Str(Left) & Str(Right));`{@,^end "&";`{{@,^function "<"(Left, Right : in Text) return Boolean is`{@,^begin`{@/^return Str(Left) < Str(Right);`{@,^end "<";`{}b[ 409B407]@3function Txt(S : in String) return Text is{@6Answer : Text;{@3begin{@6Answer.Len := S'Length;{@6Answer.Val(1 .. Answer.Len) := S;{@6return Answer;{@3end Txt;{{{True or False?  A call to Txt with the null string,^Txt("")`, will raise a{Constraint_Error.{}Please press T for true or F for false, or B to go back.[F410T411B408]@2^function Txt(S : in String) return Text is`{@5^Answer : Text;`{@2^begin`{@5^Answer.Len := S'Length;`{@5^Answer.Val(1 .. Answer.Len) := S;`{@5^return Answer;`{@2^end Txt;`{{{%You're right!~ The first executable statement will set Answer.Len to 0, and{the second executable statement will do nothing.  The check for{Constraint_Error is suppressed when a null slice is involved.  Thus the{function will work correctly even for the null string.{}q[ 412B409Q409]@3function Txt(S : in String) return Text is{@6Answer : Text;{@3begin{@6Answer.Len := S'Length;{@6Answer.Val(1 .. Answer.Len) := S;{@6return Answer;{@3end Txt;{{{False.  The function will work correctly even for the null string.  The first{executable statement will set Answer.Len to 0, and the second executable{statement will do nothing.  The check for Constraint_Error is suppressed when a{null slice is involved.{}q[ 412B409Q409]@4type Text is{@7record{@:Len : Integer range 0 .. 80 := 0;{@:Val : String(1 .. 80);{@7end record;{{There are two problems with type Text.  The way Ada assigns arrays is less than{ideal when assigning objects of type Text, and the way Ada tests for equality{is totally unacceptable.  Suppose we have^T1, T2 : Text;~and then we execute{%T1 := Txt("Hello");~and then^T2 := T1;`.  In doing the assignment, Ada will{copy all 80 characters of T1.Val, even though the last 75 characters contain{garbage and only the first 5 characters (and the Len field) need be copied.{Perhaps we could live with this inefficiency, but Ada's test for equality of{arrays creates a more serious problem.{{If we write^T1 := Txt("aaaaaaaaaa");~and^T2 := Txt("bbbbbbbbbb");~and then{%T1 := Txt("Hello");~and^T2 := Txt("Hello");`, Ada will say that T1 /= T2,{because it compares the entire Val fields:  T1.Val(6 .. 10) is "aaaaa", but{T2.Val(6 . .10) is "bbbbb".  We want Ada to compare only the first 5 characters{of T1 and T2, as both Len fields are 5.  We could modify function Txt (that{converts from String to Text) to pad the rest of the Val field with blanks, so{that the test for equality would be correct, but that would reduce efficiency.{}b[ 413B409]We could also try to get around this problem by writing our own function Equal:{{@/function Equal(T1, T2 : in Text) return Boolean is{@/begin{@2return Str(T1) = Str(T2);{@/end Equal;{{This function would work, but we might forget to write^if Equal(T1, T2)~and{write^if T1 = T2~instead.  Similarly, we could write a procedure to assign{Texts efficiently, and forget to use it and write^T2 := T1;`.{{Ada 9X lets us write a function "=" similar to the function above:{{@/function "="(T1, T2 : in Text) return Boolean is{@/begin{@2return Str(T1) = Str(T2);{@/end "=";{{This gets around the problem that we might forget to write^if Equal(T1, T2)~and{write "if T1 = T2" instead.  However, it doesn't solve the problem of assigning{Texts efficiently.  For this we need a^limited private~type.{}b[ 414B412]Ada will prevent us from assigning Texts and testing them for equality if we{create a package and make type Text^limited private`.  Outside the package there{are only^two~things we may do with objects of a limited private type:{{1. ^Create them:~ T1, T2 : Text;{{2. ^Use any procedures, functions, and infix operators provided by the package:`{@$T1 & T2@#etc.{{We can't test for equality and inequality unless the package includes a{function "=".  Also, Ada won't let us write^T2 := T1;`, but the package could{provide a procedure to assign Texts.  Here's our package specification:{}b[ 415B413]@-package Text_Handler is{@/^type Text is limited private;`{@0function Str(T : in Text) return String;{@0function Txt(S : in String) return Text;{@0function "&"(Left, Right : in Text) return Text;{@0...{@/^function "="(Left, Right : in Text) return Boolean;`{@0function "<"(Left, Right : in Text) return Boolean;{@0...{@/^procedure Set(Target : in out Text; To : in Text);`{@,^private`{@0type Text is{@3record{@6Len : Integer range 0 .. 80 := 0;{@6Val : String(1 .. 80);{@3end record;{@-end Text_Handler;{{Note that we write^type Text is limited private`, but we still introduce the{private part of the package simply with the word^private`.{{The two new subprograms are as easy to write as the others:{}b[ 416B414]@,^function "="(Left, Right : in Text) return Boolean is`{@,^begin`{@/^return Str(Left) = Str(Right);`{@,^end "=";`{{@,^procedure Set(Target : in out Text; To : in Text) is`{@,^begin`{@/^Target.Len := To.Len;`{@/^Target.Val(1 .. Target.Len) := To.Val(1 .. To.Len);`{@,^end Set;`{{In summary, we used^limited private~for type Text because Ada's definitions of{equality and assignment weren't appropriate for that type, and we wanted to{provide our own definitions.  However, Ada's definitions^were~appropriate for{Screen_Type, so we made that a^private~type to contain the effects of changes.{{In Ada 9X, the choice between private and limited private should depend on{whether we need to redefine assignment, not equality, because Ada 9X lets us{redefine "=" even if the type isn't limited private.{}b[ 417B415]@+package Stacks is{@.type Stack is^?`{@.procedure Push (S : in out Stack; Item : in  Integer);{@.procedure Pop  (S : in out Stack; Item : out Integer);{@+private{@.type Ivector is array(Integer range <>) of Integer;{@.type Stack is{@1record{@4Sp : Integer range 1 .. 11 := 1;{@4St : Ivector(1 .. 10);{@1end record;{@+end Stacks;{{Suppose we want to write a package that lets us create objects of type Stack,{and Push and Pop integers on them.  The stacks will be last in, first out.{(For now, ignore the possibilities of stack underflow and overflow.)  Should{type Stack be^private~or^limited private`?{{@31.  Type Stack should be^private`.{{@32.  Type Stack should be^limited private`.{}Please press 1 or 2, or B to go back.[24181419B416]@+package Stacks is{@-^type Stack is limited private;`{@.procedure Push (S : in out Stack; Item : in  Integer);{@.procedure Pop  (S : in out Stack; Item : out Integer);{@+private{@.type Ivector is array(Integer range <>) of Integer;{@-^type Stack is`{@0^record`{@3^Sp : Integer range 1 .. 11 := 1;`{@3^St : Ivector(1 .. 10);`{@0^end record;`{@+end Stacks;{{%You're right!~ Similar to type Text, only part of the array in type Stack (the{part up through Sp - 1) is significant; the rest contains garbage.  Thus, Ada's{test for equality is unsatisfactory for the same reason.  Also, if we wanted to{assign Stacks, we would want to copy only the significant part of the array,{not the whole array.  Therefore, type Stack should be^limited private`.{}q[ 420B417Q417]@+package Stacks is{@.type Stack is^?`{@.procedure Push (S : in out Stack; Item : in  Integer);{@.procedure Pop  (S : in out Stack; Item : out Integer);{@+private{@.type Ivector is array(Integer range <>) of Integer;{@.type Stack is{@1record{@4Sp : Integer range 1 .. 11 := 1;{@4St : Ivector(1 .. 10);{@1end record;{@+end Stacks;{{No, type Stack is similar to type Text in that only part of the array (the part{up through Sp - 1) is significant; the rest contains garbage.  Thus, Ada's test{for equality is unsatisfactory for the same reason.  Also, if we wanted to{assign Stacks, we would want to copy only the significant part of the array,{not the whole array.  Therefore, type Stack should be^limited private`.{}q[ 420B417Q417]@<HIERARCHICAL LIBRARIES{{Earlier we considered a package CRT_Controller that had procedures to draw{dots, lines, and boxes.  Suppose that we have compiled that package and several{calling programs, and then we wish to add a procedure to draw a circle.  If we{add the procedure directly to CRT_Controller, we'll have to recompile{CRT_Controller, and, as a result, all of the previously written calling{programs, because these^with~the package.  This is true even though the{previously written calling programs don't call the new procedure to draw a{circle.{{In Ada 9X, we can write a^child package~to get around this problem.  Its name{is CRT_Controller followed by a dot and another name, for example,{%CRT_Controller.More`.  This package must be compiled after the specification of{the parent, CRT_Controller.  We do not change or recompile CRT_Controller.{Instead, we put our new routines, such as Circle, in CRT_Controller.More and{compile it.{}b[ 421B417]Now the previously written calling programs that^with~CRT_Controller don't have{to be recompiled.  The new programs, that can call Circle (as well as Dot,{Line, Box, etc.) should say^with CRT_Controller.More;`.  This automatically does{%With CRT_Controller;~as well, so we don't need that second^with~statement.{However, if we want to^use~both the parent package and the child package, we{must supply both^use~statements:^use CRT_Controller; use CRT_Controller.More;`.{{Our new Ada 9X child package specification will look like this:{{@8package^CRT_Controller.More~is{@;...{@;procedure Circle ... ;{@;...{@8end CRT_Controller;{{A parent package can have several children, and the children can have children,{to any depth.  Also, a child can be a subprogram (procedure or function) as{well as a package.  Finally, the child package could have been made private to{its parent if we had begun with{{@3^private~package CRT_Controller.More is{}b[ 422B420]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Recursion and Assignment 4{{@#The Format of an Ada Program@-Subprograms and Packages`{{@#Generic Instantiation and@,^>  ACCESS TYPES, USER DEFINED TYPES,`{@&Assignment 1@<^AND DERIVED TYPES`{{@#Simple Declarations and Simple@+Exceptions, Text_IO, and{@&Attributes@?Assignment 5{{@#Operators, Control Constructs, and@'Generics, Tasking, and Assignment 6{@&Assignment 2{@LMore Records and Types{@#Records, Arrays, and Assignment 3{@LAdvanced Topics{}b[ 423B421]@BACCESS TYPES{{Access types are sometimes called "pointers" in other languages.  However, the{name "pointer" fell into disrepute, because of "dangling reference" problems.{With Ada's access types, dangling references are impossible, unless we{deliberately instantiate Unchecked_Deallocation (discussed in the Advanced{Topics section) or use the Ada 9X attribute 'Unchecked_Access (discussed later{in this section).  So Ada uses the reserved word^access`.{{If we define type Date as before, and write^USA : Date;~then USA has three{fields: Day, Month, and Year.  However, if we write{{@<^type P is access Date;`{@<^D1, D2 : P;`{{then D1 and D2 are capable of^pointing to~objects of type Date.  In most{implementations of Ada, this means that D1 and D2 can each contain the machine{address of the start of a record of type Date.  However, this detail depends on{the implementation of Ada.  D1 and D2 themselves don't have fields, but the{objects they can point to have fields.{}b[ 424B422]@<^type P is access Date;`{@<^D1, D2 : P;`{{At present D1 and D2 point to nothing.  However, if we execute^D1 := new Date;`,{then, at run time, enough memory for one record of type Date is allocated, and{D1 is made to point to it.  This new object of type Date doesn't have a name;{only the pointer, D1, has a name.  By contrast, when we elaborate^USA : Date;`{we create an object that has a name (USA), but nothing can point to it.{{We can refer to the fields of the nameless object pointed to by D1 as if D1{itself had fields.  Thus, we can write D1.Day, D1.Month, and D1.Year, and use{these on either side of an assignment:^D1.Day := 12;`.  The entire object{pointed to by D1 is^D1.all`, so we could write^D1.all := (12, Oct, 1492);`.  Note{that^D1.Day~is simply an abbreviation for^D1.all.Day`.  Similarly, if A1 points{to an array rather than a record, then^A1.all(5)~may be abbreviated^A1(5)`.{{We can execute^D2 := new Date'(4, Jul, 1776);~giving the new object a value{when it's created.  We can also declare^D3 : P := new Date;~to make D3 point to{an object when D3 is created, or even write^D3 : P := new Date'(4, Jul, 1776);`{to make D3 point to an object and also give the object a value.{}b[ 425B423]We can write^D3 := null;~to make D3 point nowhere.  When a pointer is declared{and no initialization is shown, it's automatically initialized to^null`, so{%D4 : P;~means^D4 : P := null;`.  When a pointer is null, trying to reference the{object pointed to (%D4.Day~or^D4.all`, etc.) will raise a Constraint_Error.  We{can test to see if a pointer is null:^if D4 = null then~...^end if;`.{{Copying a pointer isn't the same as copying the object pointed to.  If we{execute^D1.all := (12, Oct, 1492);~and then^D2.all := D1.all;`, the entire{record is copied.  If we change D1.Day with^D1.Day := 13;`, D2.Day is still 12.{{However, is we execute^D1.all := (12, Oct, 1492);~and then^D2 := D1;`, then the{address in D1 is copied to D2, so that D2 now points to the same place as D1.{Thus, if we change D1.Day with^D1.Day := 13;`, then D2.Day is also 13, because{it references the same memory location.{{If we have^D1 := new Date'(12, Oct, 1492);~and^D2 := new Date'(4, Jul, 1776);`{and then execute^D2 := D1;`, D2 now points where D1 points, and nothing any{longer points to the object containing (4, Jul, 1776).  Most systems cannot{automatically reclaim the memory occupied by that object.  In the Advanced{Topics section, we'll learn to use Unchecked_Deallocation to release the memory{pointed to by D2 before we execute^D2 := D1;`.{}b[ 426B424]In Ada 9X, it's possible to point to an object that has a name.  If we declare{{@5type P is access^all~Date;{@5USA :^aliased~Date := (4, Jul, 1776);{@5D1  : P;{{then we can make D1 point to USA by executing^D1 := USA'Access;`.  We can now{refer to D1.Day, D1.Month, and D1.Year as well as USA.Day, USA.Month, and{USA.Year.  If we change the first declaration above to{{@8type P is access^constant~Date;{{and then declare USA and D1 as above, and execute^D1 := USA'Access;`, then D1{has read-only access to USA.  That is, we can read, but not store into, D1.Day,{D1.Month, and D1.Year (as well as the whole record D1).  We can still read and{store into USA.Day, USA.Month, USA.Year, and the whole record USA.  If we want{to prevent ourselves from storing directly into USA, we can write{{@0USA :^aliased constant~Date := (4, Jul, 1776);{{We can still execute^D1 := USA'Access;`, but now we can't update USA either{directly or through D1; we can only read it.{}b[ 427B425]The^'Access~attribute in Ada 9X performs an^accessibility check~to assure that{the lifetime of the object pointed to is at least as long as the lifetime of{the access type.  This eliminates the danger of dangling references, that is,{pointing to an object that no longer exists in memory.  For example, the{highlighted line below is illegal and will be caught by the compiler:{{  package Schedule is@.with Schedule; use Schedule;{@%type Date is ...;@-procedure Test is{@%type P is access all Date;@'Today : aliased Date;{@%...@=^T@%: P := Today'Access; -- illegal`{  end Schedule;@4begin{@F...{@Cend Test;{{The highlighted line is illegal because^T~could be stored in a global variable{(some variable declared outside the procedure^Test`), or be passed to another{routine.  Procedure^Test~could then reach its end, causing^Today~to cease to{exist, because^Today~is declared inside^Test`.  But the copy of^T~could still{exist, and it would then point to an object that no longer exists in memory,{with unpredictable results.  Ada guards against the dangling reference problem{that plagues some other languages.{}b[ 428B426]However, Ada lets us get around the accessibility check if we want to.  The{previous example becomes legal if we replace^Today'Access~with{%Today'Unchecked_Access`:{{package Schedule is@,with Schedule; use Schedule;{@#type Date is ...;@+procedure Test is{@#type P is access all Date;@%Today : aliased Date;{@#...@;^T@%: P := Today'Unchecked_Access; -- legal`{end Schedule;@2begin{@B...{@?end Test;{{In this case, the programmer must be very careful to assure that no copies of^T`{are ever referenced when the object pointed to (%Today`) has gone out of{existence.{{We'll discuss accessibility checks further when we talk about access parameters{in the section on More Records and Types.{}b[ 429B427]Access types are especially useful for creating^linked lists`.  A simple linked{list can be thought of as a chain.  Each link contains some useful data{(perhaps an integer, perhaps pages of information), and a pointer to the next{item in the chain.  There's also a pointer, usually called Head, that points to{the first link in the chain.  The last link points nowhere.{{A linked list of integers might look something like this:{@'^ ____@'__________@*__________@*__________ `{@'^|  --|---->| Int@#10 |@#,--->| Int@#27 |@#,--->| Int@#34 |`{@'^|____|@%| Next  ---|---'@$| Next  ---|---'@$| Next null|`{@'^ Head@&|__________|@(|__________|@(|__________|`{{To add another integer to the chain, keeping the integers in ascending order,{we simply break the chain at the appropriate point and insert another link.{{To set up our linked list, we'd like to write^type P is access Link;~and write{{@<^type Link is`{@?^record`{@B^Int  : Integer;`{@B^Next : P;`{@?^end record;`{}b[ 430B428]However, the declaration of type P involves Link, and the declaration of type{Link involves P, so neither declaration can come first!  Ada provides a special{means of solving this problem.  We can write{{@<^type Link;`{@<^type P is access Link;`{@<^type Link is`{@?^record`{@B^Int  : Integer;`{@B^Next : P;`{@?^end record;`{{The first line is called an^incomplete type declaration`.  It simply tells the{compiler that type Link exists.  That's all the information the compiler needs{to compile the second line.  The second line tells the compiler that objects of{type P will contain pointers, but for this line the compiler doesn't need to{know details of the objects pointed to.  The second line must be followed by{the full declaration of type Link.{}b[ 431B429]@4type Person is{@7record{@:Name : String(1 .. 10);{@:Age  : Natural;{@7end record;{@4type P is access Person;{@4P1 : P := new Person'("Susan@%", 21);{@4P2 : P := new Person'("John@&", 35);{@4...{@4P2 := P1;{@4P1.Age := 22;{{{@?What is P2.Age?{{@?1.  P2.Age is 21.{{@?2.  P2.Age is 22.{{@?3.  P2.Age is 35.{}Please press 1, 2, or 3, or B to go back.[243214333433B430]@4type Person is{@7record{@:Name : String(1 .. 10);{@:Age  : Natural;{@7end record;{@4type P is access Person;{@4P1 : P := new Person'("Susan@%", 21);{@4P2 : P := new Person'("John@&", 35);{@4...{@4P2 := P1;{@4P1.Age := 22;{{{%You're right!~ The last line changed P1.Age to 22.  Since the previous line{made P2 point where P1 points, P2.Age is also 22.{}q[ 434B431Q431]@4type Person is{@7record{@:Name : String(1 .. 10);{@:Age  : Natural;{@7end record;{@4type P is access Person;{@4P1 : P := new Person'("Susan@%", 21);{@4P2 : P := new Person'("John@&", 35);{@4...{@4P2 := P1;{@4P1.Age := 22;{{{No, the last line changed P1.Age to 22.  Since the previous line made P2 point{where P1 points, P2.Age is also 22.{}q[ 434B431Q431]Let's use an access type to write a program that gets integers in random order{from the keyboard, maintaining a linked list of them.  When^0~is input, the{program outputs the integers in ascending order.  This program will be a good{stepping-stone to Outside Assignment 5.  To simplify inserting an integer into{the linked list, Head will point to an unused Link, which will in turn point to{the first actual link in the chain:{{% ____@&__________@)__________@)__________@)__________{|  --|--->| Int@&|@#,-->| Int@#10 |@#,-->| Int@#27 |@#,-->| Int@#34 |{|____|@$| Next  ---|---'@#| Next  ---|---'@#| Next  ---|---'@#| Next null|{ Head@%|__________|@'|__________|@'|__________|@'|__________|`{{We could create our linked list using arrays rather than an access type.{However, we'd have to specify the size of the arrays, placing a limit on the{number of integers the program can handle.  With the access type, the only{limit is the amount of available memory.  We'll be able to move our program to{a larger machine to increase this limit, without changing any code - not even{one line to specify the size of an array.{{Here's our program ...{}b[ 435B431]@(with Text_IO; use Text_IO;{@(procedure LL_Demo is{@+package My_Int_IO is new Integer_IO(Integer); use My_Int_IO;{@+type Link;{@+type P is access Link;{@+type Link is{@.record{@1Int  : Integer;{@1Next : P;{@.end record;{@*^Head : P := new Link;`{@*^I@$: Integer;`{@*^procedure Add_I_To_Linked_List is separate;`{@*^procedure Display_Linked_List is separate;`{@(begin{@*^Put("Type an integer: ");  Get(I);  Skip_Line;`{@*^while I /= 0 loop`{@-^Add_I_To_Linked_List;`{@-^Put("Type an integer: ");  Get(I);  Skip_Line;`{@*^end loop;`{@*^Display_Linked_List;`{@(end LL_Demo;{}b[ 436B434]^separate (LL_Demo)`{^procedure Display_Linked_List is`{@#^Tmp : P := Head.Next;@*-- Skip unused link at the head of the list.`{^begin`{@#^while Tmp /= null loop`{@&^Put(Tmp.Int);  New_Line;@)-- Display integer in the current link.`{@&^Tmp := Tmp.Next;@9-- Go to next link in the list.`{@#^end loop;`{^end Display_Linked_List;`{{^separate (LL_Demo)`{^procedure Add_I_To_Linked_List is`{@#^Tmp : P := Head;@'-- Begin search of where to insert at start of list.`{^begin`{@#^while Tmp /= null and then Tmp.Next /= null and then Tmp.Next.Int < I loop`{@&^Tmp := Tmp.Next;  -- Note use of "and then" to avoid trying to reference`{@#^end loop;@,-- the object pointed to when the pointer is null.`{@#^Tmp.Next := new Link'(I, Tmp.Next);  -- Create new link and insert in list.`{^end Add_I_To_Linked_List;`{{The best way to follow these two subprograms is to draw a linked list on a{piece of scrap paper and "hand execute" the subprograms.{}b[ 437B435]@3type Link; ^-- 1`{@3type P is access Link;{@3type Link is{@6record{@9F : Float; ^-- 2`{@9S : String(1 .. 10); ^-- 3`{@9A : array(1 .. 10) of Integer; ^-- 4`{@6end record;{@3L1 : Link; ^-- 5`{@3P1 : P;{{Which commented line in the above is^illegal`?{}Please press 1, 2, 3, 4, or 5, or B to go back.[44381439244034415442B436]@3type Link;  -- 1{@3type P is access Link;{@3type Link is{@6record{@9F : Float;  -- 2{@9S : String(1 .. 10);  -- 3{@8^A : array(1 .. 10) of Integer;  -- 4`{@6end record;{@3L1 : Link;  -- 5{@3P1 : P;{{{%You're right!~ Inside a record definition, the name of a field must be{followed by a type name, not^array`.  We would first have to say something like{%type List is array(Integer range <>) of Integer;`, and then change the field{definition to{{@8^A : List(1 .. 10);`{}q[ 443B437Q437]@3type Link;  -- 1{@3type P is access Link;{@3type Link is{@6record{@9F : Float;  -- 2{@9S : String(1 .. 10);  -- 3{@9A : array(1 .. 10) of Integer;  -- 4{@6end record;{@3L1 : Link;  -- 5{@3P1 : P;{{{No, the first line is legal.  Ada allows an incomplete type declaration to{precede the declaration of an access type, provided the complete type{declaration follows.{}q[ 443B437Q437]@3type Link;  -- 1{@3type P is access Link;{@3type Link is{@6record{@9F : Float;  -- 2{@9S : String(1 .. 10);  -- 3{@9A : array(1 .. 10) of Integer;  -- 4{@6end record;{@3L1 : Link;  -- 5{@3P1 : P;{{{No, the declaration of F inside the record definition is legal, because Ada{records may contain fields of any type.{}q[ 443B437Q437]@3type Link;  -- 1{@3type P is access Link;{@3type Link is{@6record{@9F : Float;  -- 2{@9S : String(1 .. 10);  -- 3{@9A : array(1 .. 10) of Integer;  -- 4{@6end record;{@3L1 : Link;  -- 5{@3P1 : P;{{{No, the declaration of S inside the record definition is legal, because Ada{records may contain fields of any type.{}q[ 443B437Q437]@3type Link;  -- 1{@3type P is access Link;{@3type Link is{@6record{@9F : Float;  -- 2{@9S : String(1 .. 10);  -- 3{@9A : array(1 .. 10) of Integer;  -- 4{@6end record;{@3L1 : Link;  -- 5{@3P1 : P;{{{No, the declaration of L1 as type Link is legal.  Even though type P was{declared to be^access Link~and we ordinarily would declare objects to be of{type P, we may also directly declare objects to be of type Link.  Of course,{nothing can point to such objects.{}q[ 443B437Q437]In Ada 9X an access type can access a subprogram.  Thus, the system can decide{%at run time~which of several subprograms to call.  This is called^Dynamic{Selection`.  For example:{{@$package P is{@&^type Int_Function is access function(X : in Integer) return Integer;`{@'F : array(1 .. 2) of Int_Function;{@'function Square(X : in Integer) return Integer;{@'function Cube(X : in Integer) return Integer;{@$end P;{{@$with P; use P;{@$procedure Dynamic_Selection_Demo is{@'X, Y : Integer;{@$begin{@'F(1) := Square'Access;{@'F(2) := Cube'Access;{@'X := 3;{@'for I in 1 ..2 loop{@)^Y := F(I)(X); -- Decides at run time which function to call.`{@'end loop;{@$end Dynamic_Selection_Demo;{}b[ 444B437]@'F(1) := Square'Access;{@'F(2) := Cube'Access;{@'X := 3;{@'for I in 1 ..2 loop{@)^Y := F(I)(X); -- Decides at run time which function to call.`{@'end loop;{{Note that^F(I)(X)~is simply an abbreviation for^F(I).all(X)`.  The first time{through the loop, the highlighted line above will call the function Square and{set Y to 9; the second time through the loop the same line will call Cube and{set Y to 27.{{In the section on More Records and Types, under Tagged Records and Dynamic{Dispatching, we'll learn another way to make an Ada 9X system decide at run{time which of several subprograms to call.{}b[ 445B443]In Ada 9X, pointers to subprograms may also be used as parameters ("dummy{arguments") of other subprograms. For example:{{@3procedure Demo (%Fcn : in Int_Function`) is{@6X, Y : Integer;{@3begin{@6...{@6Y := Fcn(X);{@6...{@3end Demo;{{If F(1) was set to Square'Access, we could then call Demo with^Demo(F(1));`, and{Demo would set Y to Square(X).  If F(2) is Cube'Access and we call^Demo(F(2));`,{Demo then sets Y to Cube(X).  When Demo calls function Square or function Cube,{this action is called^call back`.{}b[ 446B444]@7USER DEFINED TYPES AND PORTABILITY{{In some implementations of Ada, Integers are represented by 32-bit two's{complement numbers, giving the range -2_147_483_648 .. 2_147_483_647.  Other{implementations use 16-bit two's complement Integers, giving the range{-32768 .. 32767.  However, some of the 16-bit implementations also provide a{32-bit type called Long_Integer.{{Suppose we need a variable called Number to count from zero to one million.  We{could declare^Number: Integer;~for the 32-bit implementation, and change this{to^Number : Long_Integer;~when we port the program to a machine running a{16-bit version that provides Long_Integer.  However, we could also declare{{@4^type Counter is range 0 .. 1_000_000;`{@4^Number : Counter;`{{and both implementations of Ada will automatically select the appropriate{internal representation for our type Counter!  The 32-bit Ada will select{Integer, and the 16-bit Ada will select Long_Integer.  This gives us the{advantage that no code has to be changed when the program is ported.  Counter{is called a^user-defined type`.  Of course, we must use explicit type{conversion to mix objects of type Counter with objects of other types.{}b[ 447B445]Similarly, different implementations of Ada provide different representations{for type Float, and some provide a type Long_Float.  We can declare{{@<^type Real is digits 8;`{@<^F : Real;`{{and be certain that F will have at least 8 digits of accuracy on any machine{that accepts this type declaration.  A range constraint is optional.{{User defined types also apply to fixed point numbers; these will be discussed{in the section on More Records and Types.{{It's possible to make a declaration that will be accepted by only some{implementations of Ada.  For example, if we declare{{@3^type X is digits 30 range 0.0 .. 100.0;`{{some implementations of Ada might have to report that there's no available type{that gives at least 30 digits of accuracy.{{No language can give perfectly portable programs, but Ada truly advanced the{state of the art in portability.{}b[ 448B446]@ADERIVED TYPES{{Derived types are created to prevent accidental mixing of objects.  Unlike{subtypes, derived types are distinct types.  For example,{{@.^type No_Of_Apples  is new Integer;`{@.^type No_Of_Oranges is new Integer range 0 .. 100;`{@.^NOA : No_Of_Apples;`{@.^NOO : No_Of_Oranges;`{@.^I@#: Integer;`{@/...{@.^NOA := NOA + NOO;  -- illegal`{@.^NOA := NOA + NOA;`{@.^NOA := NOA + I;  -- illegal`{@.^NOA := NOA + No_Of_Apples(I);`{@.^NOA := NOA + No_Of_Apples(NOO);`{{A derived type is denoted by the reserved word^new~followed by an existing type{like Integer.  The operations that Ada knows for Integers, such as addition,{are "inherited" by the derived types so that, for example, Ada knows how to add{two objects of type No_Of_Oranges.  As the examples above show, we can't mix{types accidentally, but we can deliberately mix them by converting first.{}b[ 449B447]In summary,{{{@*^Subtypes~are usually created to provide range constraints:{{@0^subtype Day_Subtype is Integer range 1 .. 31;`{{{@'^Derived types~are usually created to prevent accidental mixing:{{@3^type No_Of_Apples  is new Integer;`{@3^type No_Of_Oranges is new Integer~...^;`{{{@)^User-defined types~are usually created to gain portability:{{@4^type Counter is range 0 .. 1_000_000;`{@4^type Real@$is digits 8;`{}b[ 450B448] type Meters@,is new Float;{ type Seconds@+is new Float;{ type Meters_Per_Second is new Float;{ ...{ function "*"(Left : in Meters_Per_Second; Right : in Seconds) return Meters is{ begin{@$return Meters(Left) * Meters(Right);{ end "*";{ function "*"(Left : in Seconds; Right : in Meters_Per_Second) return Meters is{ begin{@$return Right * Left;{ end "*";{ function "/"(Left : in Meters; Right : in Seconds) return Meters_Per_Second is{ begin{@$return Meters_Per_Second(Left) / Meters_Per_Second(Right);{ end "/";{{@1The above program segment is an example of ...{@11.  derived types.{@12.  user-defined types.{@13.  subtypes.{}Please press 1, 2, or 3, or B to go back.[145124523453B449] type Meters@,is^new~Float;{ type Seconds@+is^new~Float;{ type Meters_Per_Second is^new~Float;{{{%You're right!~ The reserved word^new~in the segment above tells us that we're{defining derived types.{}q[ 454B450Q450] type Meters@,is new Float;{ type Seconds@+is new Float;{ type Meters_Per_Second is new Float;{{{No, examples of user-defined types are{{@5type Counter is range 0 .. 1_000_000;{@5type Real@$is digits 8;{}q[ 454B450Q450] type Meters@,is new Float;{ type Seconds@+is new Float;{ type Meters_Per_Second is new Float;{{{No, subtypes are usually created to provide range constraints.{}q[ 454B450Q450]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Recursion and Assignment 4{{@#The Format of an Ada Program@-Subprograms and Packages`{{@#Generic Instantiation and@0Access Types, User Defined Types,{@&Assignment 1@=and Derived Types{{@#Simple Declarations and Simple@'^>  EXCEPTIONS, TEXT_IO, AND`{@&Attributes@>^ASSIGNMENT 5`{{@#Operators, Control Constructs, and@'Generics, Tasking, and Assignment 6{@&Assignment 2{@LMore Records and Types{@#Records, Arrays, and Assignment 3{@LAdvanced Topics{}b[ 455B450]@CEXCEPTIONS{{When an error occurs during the elaboration or execution of a statement, Ada is{said to^raise an exception`.  Ordinarily this stops the program, but Ada{programs can trap exceptions and execute a special block of code when one{occurs.  This code is called an^exception handler`.{{We can define our own exceptions, but five of them are predefined by Ada:{{%Constraint_Error`{@%This is the exception encountered most often by beginners, because it can{be caused by a number of different things.  It can be raised by a subscript out{of range, a subtype out of range (USA.Day := 32;), an attribute used improperly{(Integer'Value("12X3") or Month_Type'Val(13)), assigning an array of one length{to a destination of another (H : String(1 .. 5) := "Hi";), or by attempting to{access an object with a null pointer.{{%Numeric_Error`{@%Many implementations of Ada raise this on an arithmetic overflow or an{attempt to divide by zero.  The newest implementations of Ada raise{Constraint_Error instead.  (In Ada 9X, Numeric_Error merely renames{Constraint_Error.){}b[ 456B454]%Program_Error`{@%This is rarely encountered by beginners, but it can be raised by skipping{around the^return~statement in a function and running into the^end~statement.{{%Storage_Error`{@%This is raised by running out of memory, as with a recursive program{calling itself unconditionally or an attempt to create an infinitely large{linked list.{{%Tasking_Error`{@%This will be discussed in the section on Tasking.{{An exception handler is introduced by the reserved word^exception`; its{structure is similar to that of a^case~construct.  We'll see an example in a{moment.  Unlike a^case~construct, an exception handler need not account for all{the possibilities.{{An exception handler can be placed in a subprogram, in the initialization code{of a package, in a task (to be discussed in the section on Tasking), or in a{block (to be discussed later in this section).  Here's a procedure with an{exception handler that handles an exception,^Wrong`, that we declare ourselves,{as well as the built-in exceptions^Constraint_Error~and^Numeric_Error`:{}b[ 457B455] with Text_IO; use Text_IO;{ procedure Exception_Demo is{@$package My_Int_IO is new Integer_IO(Integer); use My_Int_IO;{@$I@%: Integer;{@#^Wrong : exception;`{ begin{@$loop{@'New_Line(2);  Put("Type a positive integer. ");  Get(I);  Skip_Line;{@'if I <= 0 then{@)^raise Wrong;`{@'end if;{@'Put("The square is ... ");{@&^Put(I*I); -- Raises Constraint_Error or Numeric_Error if I is too large.`{@$end loop;{^exception`{@#^when Constraint_Error | Numeric_Error =>`{@'Put(" ... too big.");{@#^when Wrong =>`{@'New_Line;{@'Put("I said Positive integer!");{ end Exception_Demo;{}b[ 458B456]We can deliberately raise an exception (either user-defined or built-in) with{the^raise~statement, as in^raise Wrong;~or^raise Constraint_Error;`.  Also,{ordinary statements can raise exceptions.  In our sample program,^Put(I*I);`{raises Constraint_Error or Numeric_Error if I is too large.  When an executable{statement raises an exception, the exception handler is executed^instead of~the{rest of the procedure, function, etc.  Our program keeps asking for integers{and displaying their squares until an exception is raised.  Then, the exception{handler is executed, and there's no way to get back into the procedure to ask{for another integer (short of a recursive call).  Even a^goto~from the{exception handler to the main part of the procedure is forbidden.  Soon we'll{show how the block construct can overcome this problem, so that our program{will continue to ask for more integers even after an exception is handled.{{As with^case~constructs, an exception handler may use the vertical bar to{denote multiple choices (%when Constraint_Error | Numeric_Error =>~block of{code), and it may say^when others =>~to handle all cases not covered earlier.{But there's no way to test, inside the exception handler,^which line~raised the{exception.  We can only test^which kind~of exception was raised.{{Don't use exceptions where a simple^if~will do.  In our program, trapping the{arithmetic overflow was OK, but the^if~could have handled I <= 0 without{raising Wrong.  This exception was declared only to give a simple example.{}b[ 459B457]@>1.  Constraint_Error{{@>2.  Numeric_Error{{@>3.  Program_Error{{@>4.  Storage_Error{{@>5.  Tasking_Error{{{Assuming Rainbow_Color and Traffic_Light_Color are defined as before, which of{the above exceptions would be raised by^Rainbow_Color'Value("AMBER")`?{}Please press 1, 2, 3, 4, or 5, or B to go back.[14602461346244635464B458]@=^1.  Constraint_Error`{{@>2.  Numeric_Error{{@>3.  Program_Error{{@>4.  Storage_Error{{@>5.  Tasking_Error{{{%You're right!~ Using an attribute improperly in this way will raise{Constraint_Error.{}q[ 465B459Q459]@>1.  Constraint_Error{{@>2.  Numeric_Error{{@>3.  Program_Error{{@>4.  Storage_Error{{@>5.  Tasking_Error{{{No, Numeric_Error is usually raised by arithmetic overflow, or attempted{division by zero.{}q[ 465B459Q459]@>1.  Constraint_Error{{@>2.  Numeric_Error{{@>3.  Program_Error{{@>4.  Storage_Error{{@>5.  Tasking_Error{{{No, Program_Error is usually raised by skipping around the^return~statement in{a function.{}q[ 465B459Q459]@>1.  Constraint_Error{{@>2.  Numeric_Error{{@>3.  Program_Error{{@>4.  Storage_Error{{@>5.  Tasking_Error{{{No, Storage_Error is raised by running out of memory.{}q[ 465B459Q459]@>1.  Constraint_Error{{@>2.  Numeric_Error{{@>3.  Program_Error{{@>4.  Storage_Error{{@>5.  Tasking_Error{{{No, Tasking_Error is raised only by programs using tasking, which we haven't{yet discussed.{}q[ 465B459Q459]A block construct lets us declare objects in the^executable~region of the{program.  For example, in the following, I and F come into existence where{they're declared, and go out of existence at the following^end~statement:{{@<procedure Block_Demo is{@?Q : Float;{@<begin{@?Q := 0.0;{@>^declare`{@A^I : Integer;`{@A^F : Float;`{@>^begin`{@A^I := 5;`{@A^F := Q;`{@>^end;`{@?Q := Q + 3.0;{@<end Block_Demo;{{However, the usual use of a block is to localize an exception handler, not to{bring objects into existence in the executable region of a program.  The{declarative part of the block is optional.  For example, let's rewrite{Exception_Demo to make use of a block with an exception handler.{}b[ 466B459] with Text_IO; use Text_IO;{ procedure Exception_Demo is{@$package My_Int_IO is new Integer_IO(Integer); use My_Int_IO;{@$I@%: Integer;{@$Wrong : exception;{ begin{@$loop{@&^begin`{@*New_Line(2);  Put("Type a positive integer. ");  Get(I);  Skip_Line;{@*if I <= 0 then{@-raise Wrong;{@*end if;{@*Put("The square is ... ");{@*Put(I*I);{@&^exception`{@*when Constraint_Error | Numeric_Error =>{@-Put(" ... too big.");{@*when Wrong =>{@-New_Line;  Put("I said Positive integer!");{@&^end;`{@$end loop;{ end Exception_Demo;{}b[ 467B465]Note that in our rewritten program, a block with an exception handler has been{created inside the loop.  Now, if an exception occurs, the handler will be{executed instead of the rest of the^block`, not the rest of the^procedure`.{Thus, the loop will still be executed, and the program will continue to ask{for integers after an exception is handled.{{There are two advantages to confining exception handlers to small blocks.{First, we narrow down the range of statements that might have raised the{exception.  Recall that the handler can't test which line raised the exception,{but it must have been one of the lines in the block.  (If an exception is{raised outside the block, our program provides no handler for it.)  Second,{program execution will continue after the end of the block.{{If an exception occurs for which there's no handler, the exception reaches the{next higher level.  For example, if the block in Exception_Demo somehow raises{Storage_Error and doesn't handle it, an exception handler for the whole{procedure would get a chance to handle it.  (In our case, there is none.)  If{it's still unhandled, it's as if the^call~to Exception_Demo raised{Storage_Error.  If the caller doesn't handle it, the exception reaches the{caller's caller, etc.  If the exception reaches the main program and is still{unhandled, the program is stopped and the system displays the name of the{exception.  However, exceptions that are handled don't even reach the caller.{}b[ 468B466]In the unusual case of an exception raised in the^declarative~region, the unit{raising the exception (subprogram, block, etc.) is^not~given a chance to handle{it.  Exceptions raised in the declarative region immediately reach the next{higher level.{{In a handler, the word^raise~may be used without a name of an exception to{re-raise whatever exception brought control to the handler.  This is especially{useful after^when others =>`, because any one of a number of exceptions might{have transferred control there.  For example,{{@1when others =>{@4Put_Line("I don't know what went wrong.");{@4-- Close files and do general cleanup.{@3^raise;`{{This lets us do some processing of the error, and still lets the next higher{level do additional processing.  Note that it's superfluous to say simply^when{others => raise;~because the exception will reach the next higher level even if{that code is omitted.  Any unhandled exception reaches the next higher level.{{An error occurring^in an exception handler~is unhandled and reaches the next{higher level (unless it occurs in a block with its own exception handler).{}b[ 469B467]In Ada 9X, it's possible to get some information about an exception, even in{the^when others~branch of an exception handler.  The package Ada.Exceptions{provides a type Exception_Occurrence and three functions (Exception_Name,{Exception_Message, and Exception_Information) that take an object of type{Exception_Occurrence and return a String.  We can declare an object of type{Exception_Occurrence and use it in an exception handler as follows:{{@,...{@+^Fault : Ada.Exceptions.Exception_Occurrence;`{@,...{@)begin{@,...{@)exception{@,...{@,when^Fault :~others =>{@/...{@/Text_IO.Put_Line(%Ada.Exceptions.Exception_Name(Fault)`);{@/...{{A warning:  When a handler for Storage_Error is reached, there may not be{enough memory to use Text_IO or Exception_Name, etc.  An attempt to do so may{just re-raise Storage_Error, bypassing your handler.{}b[ 470B468]@*with Text_IO; use Text_IO;@-separate (One){@*procedure One is@7procedure Two is{@-procedure Two is separate;@-Cain : exception;{@*begin@Bbegin{@-Two;@Craise Cain;{@*exception@>exception{@-when others =>@9when others =>{@0Put_Line("1");@9Put_Line("2");{@*end One;@?end Two;{{{@6What will the above program display?{{@61.  The program will display 1.{{@62.  The program will display 2.{}Please press 1 or 2, or B to go back.[24711472B469]@*with Text_IO; use Text_IO;@-separate (One){@*procedure One is@7procedure Two is{@-procedure Two is separate;@-Cain : exception;{@*begin@Bbegin{@,^Two;~@A^raise Cain;`{@*exception@>exception{@-when others =>@8^when others =>`{@0Put_Line("1");@8^Put_Line("2");`{@*end One;@?end Two;{{{%You're right!~ Two handles the exception, so it never reaches One.{}q[ 473B470Q470]@*with Text_IO; use Text_IO;@-separate (One){@*procedure One is@7procedure Two is{@-procedure Two is separate;@-Cain : exception;{@*begin@Bbegin{@-Two;@Craise Cain;{@*exception@>exception{@-when others =>@9when others =>{@0Put_Line("1");@9Put_Line("2");{@*end One;@?end Two;{{{No, Two handles the exception, so it never reaches One.{}q[ 473B470Q470]@?MORE ABOUT TEXT_IO{{We're almost ready for Outside Assignment 5.  For that assignment, we had to{cover type Text, access types, and exceptions.  We also need to learn a little{more about Text_IO before we do the assignment.{{Text_IO is used for input and output to and from text files as well as input{and output to and from the terminal.  Text files are files that can be listed{at the terminal.  (Binary files and random access files are handled with the{packages Sequential_IO and Direct_IO, which will be discussed in the Advanced{Topics section.){{The full specification of Text_IO appears in section 14.3.10 of the LRM.  It's{rather long, and some of the procedures and functions are rarely used.  So{there's a simplified specification of Text_IO in your printed course notes,{starting on page 17.  Please consult your printed course notes during the{following discussion.{{Note that there's a limited private type called File_Type.  For each file that{our program will use, we must create an object of this type, for example,{%F1, F2 : File_Type;`.  We can then use these objects in the procedures Create{and Open, to associate file names with the objects of type File_Type.{}b[ 474B470]Note that the I/O procedures, such as New_Line, Put, and Get, have one version{for use with the terminal, and another version for use with a file.  The file{version takes an object of type File_Type,^not~the name of the file.  The file{must first have been Created or Opened.{{The exception Status_Error is raised by trying to do I/O on a closed file.{Mode_Error is raised by trying to read from a file opened or created with mode{Out_File, or by trying to write to a file of mode In_File.  Name_Error is{raised by trying to Open a file that doesn't exist, or by trying to Create a{file with a name not allowed by the system.  End_Error is raised by trying to{read past an end-of-file.{{New_Line creates one or more blank lines on^output`, and Skip_Line skips one or{more lines of^input`.  We can Put characters and strings, and we can Put_Line a{string.  We can Get a character, and Get_Line a string.  Note that when we{Get_Line a string, the procedure returns the number of characters that were in{the line.  Thus, if we have^S : String(1 .. 80);  Len : Integer;~and we execute{%Get_Line(S, Len);~and the user types^Hello~followed by CR, Len will be set to{5, S(1 .. 5) will be set to "Hello", and the rest of S will be unmodified.{{The generic package Integer_IO can be instantiated for any integer type,{including user-defined types and derived types like Counter and No_Of_Apples.{}b[ 475B473]When we call Put in our instantiation of Integer_IO, we can optionally specify{the width and the base.{{The generic package Float_IO can be instantiated for any floating point type,{such as Float and the user-defined type Real that we created earlier.  Put{allows us optionally to specify the number of places before and after the{decimal point, and the size of the optional exponent field.{{The generic package Enumeration_IO can be instantiated for any enumeration{type.  Put allows us optionally to specify the width.{{Text_IO contains another generic package Fixed_IO for fixed point types, not{shown in our simplified version.  Fixed point types will be discussed in the{section on More Records and Types.{{To illustrate the use of Text_IO, here's a simple program that prompts for the{names of an old input file and a new output file, and copies the input file to{the output.  It's assumed that the input file is an ASCII text file no wider{than 80 characters, and that it contains no special control characters such as{form feeds:{}b[ 476B474]@(^with Text_IO; use Text_IO;`{@(^procedure Filecopy is`{@+^F1, F2 : File_Type;`{@+^S@&: String(1 .. 80);`{@+^Len@$: Integer;`{@(^begin`{@+^Put("Input file: ");  Get_Line(S, Len);`{@+^Open(File => F1, Mode => In_File, Name => S(1 .. Len));`{@+^Put("Output file: ");  Get_Line(S, Len);`{@+^Create(File => F2, Mode => Out_File, Name => S(1 .. Len));`{@+^while not End_Of_File(F1) loop`{@.^Get_Line(F1, S, Len);`{@.^Put_Line(F2, S(1 .. Len));`{@+^end loop;`{@+^Close(F1);`{@+^Close(F2);`{@(^end Filecopy;`{{In many systems, all files are closed automatically when the main program{terminates, and this program would work even without^Close(F1);~and^Close(F2);`.{{This program also appears on page 19 of your printed course notes.{}b[ 477B475]There's no way to test whether a file already exists without trying to Open it{and trapping the Name_Error if the file doesn't exist.  The following function{determines whether a file name represents an existing file.  It appears on page{19 of your printed course notes:{{@+^with Text_IO; use Text_IO;`{@+^function Exists(File_Name : in String) return Boolean is`{@.^F@&: File_Type;`{@.^Answer : Boolean := True;`{@+^begin`{@.^begin`{@1^Open(F, In_File, File_Name);`{@1^Close(F);`{@.^exception`{@1^when Name_Error => Answer := False;`{@.^end;`{@.^return Answer;`{@+^end Exists;`{}b[ 478B476]@@1.  Status_Error{{@@2.  Mode_Error{{@@3.  Name_Error{{@@4.  End_Error{{{@&Which exception is raised by attempting to do I/O on a closed file?{}Please press 1, 2, 3, or 4, or B to go back.[1479248034814482B477]@?^1.  Status_Error`{{@@2.  Mode_Error{{@@3.  Name_Error{{@@4.  End_Error{{{%You're right!~ Status_Error is raised by an attempt to do I/O on a closed file.{}q[ 483B478Q478]@@1.  Status_Error{{@@2.  Mode_Error{{@@3.  Name_Error{{@@4.  End_Error{{{No, Mode_Error is raised by an attempt to read from a file of mode Out_File, or{write to a file of mode In_File.{}q[ 483B478Q478]@@1.  Status_Error{{@@2.  Mode_Error{{@@3.  Name_Error{{@@4.  End_Error{{{No, Name_Error is raised by an attempt to Open a file that doesn't exist, or{Create a file with an illegal name.{}q[ 483B478Q478]@@1.  Status_Error{{@@2.  Mode_Error{{@@3.  Name_Error{{@@4.  End_Error{{{No, End_Error is raised by an attempt to read past an end-of-file.{}q[ 483B478Q478]@.OUTSIDE ASSIGNMENT 5 - WRITING A SIMPLE LINE EDITOR{{We're finally ready for the next Outside Assignment!  This assignment will give{you a chance to write a program of greater complexity than the previous{assignments.  By the time you've completed Outside Assignment 5, you should{feel comfortable with Ada.  The full set of requirements for the line editor we{want you to write are in your printed course notes, starting on page 20.  We'll{discuss them briefly here.  No test driver is supplied, but after you've{written the program, we'll give you some tests to perform manually on your line{editor.  You've completed the assignment when your editor passes all the tests.{{Imagine that your screen editor is unavailable to a particular user, perhaps{because the user is dialing your computer from a remote location, and your{screen editor writes directly to the screen.  You want to write a line editor.{While your computer already has a line editor called EDLIN, it's difficult to{learn to use.  The line editor you'll write, called Ledit, will take almost no{effort to learn.  The only commands are LIST and EXIT.{{The user begins each line of text with a line number, similar to Basic.  Line{numbers must be integers between 1 and 29999.  Regardless of the order in which{lines are entered, Ledit maintains a linked list of lines in order by number,{so that it can List the text in order, or write it to a file.{}b[ 484B478]Line numbers need not be consecutive, and they may be preceded by any number of{spaces.  For example, if we type{{%40 -- This is a comment.{@#20 begin{10 with Text_IO; use Text_IO;{@&30 end Add;`{{and then type^LIST`, the editor displays{{@#10 with Text_IO; use Text_IO;{@#20 begin{@#30 end Add;{@#40 -- This is a comment.{{To^insert~lines, we merely type lines with intermediate line numbers.  In our{example, if we now type{{%15 procedure Hello is{LIST`{{we'll see{}b[ 485B483]@#10 with Text_IO; use Text_IO;{@#15 procedure Hello is{@#20 begin{@#30 end Add;{@#40 -- This is a comment.{{To^replace~a line, we simply retype the line with the same line number as the{line to be replaced, and to^delete~a line, we type only the line number.  If{we now type{{%15 procedure Add is{40{LIST`{{we'll see{{@#10 with Text_IO; use Text_IO;{@#15 procedure Add is{@#20 begin{@#30 end Add;{}b[ 486B484]Thus the user can insert, replace, and delete lines by line numbers, without{learning any commands!  If the user forgets the space after the line number, no{harm is done; Ledit takes^20begin~the same as^20 begin`.  However, the user can{indent code by adding^extra~spaces after the line number.  The following{example has three^extra~spaces after each line number (four spaces total):{{%24@$Put(2 + 2);{26@$New_Line;{18@$package My_Int_IO is new Integer_IO(Integer); use My_Int_IO;{LIST`{{@#10 with Text_IO; use Text_IO;{@#15 procedure Add is{@#18@$package My_Int_IO is new Integer_IO(Integer); use My_Int_IO;{@#20 begin{@#24@$Put(2 + 2);{@#26@$New_Line;{@#30 end Add;{{When Listing, Ledit always allows exactly five spaces for the line number, so{that the text lines up correctly:{}b[ 487B485]%LIST`{{@$2 This is a sample listing,{@#20 showing how the text{  200 lines up, even when{ 2000 some line numbers are{20000 longer than others.{{When we type^EXIT`, Ledit writes the output file^without~the line numbers.  The{text above would all start in column 1 of the output file.{{For Ledit to be useful with files larger than a page, it must be possible to{list a range of lines:{{%LIST 20 - 30`{{This is only a summary of the requirements for Ledit.  Please refer to pages{20-24 of your printed course notes for the actual requirements.  As a point of{reference, our solution requires about 180 lines of Ada on four pages.{{Here are the steps to follow for Outside Assignment 5.  They can also be found{in the printed course notes on page 25:{}b[ 488B486]1.  Carefully read the requirements starting on page 20 of the printed course{@$notes.  Take your time.{{2.  Write the Ada code, compile, and link.  Call the main program Ledit.  If{@$you have any questions about what Ledit should do, you can compile and run{@$our solution, which is in LEDIT.ANS.{{3.  Refer to pages 26-28 of the printed course notes for instructions on{@$testing your line editor.  If any tests are failed, go back to step 2.{{4.  When all the tests are passed, you've completed the assignment and will{@$have a chance to compare your solution with ours.{{{Please type X to exit^ADA-TUTR~temporarily, and try Outside Assignment 5.  It{will probably take several days.  Take your time; there's no deadline.  Good{luck!{}Please type X to exit, a space to go on, or B to go back.[ 489B487]@-^Congratulations on Completing Outside Assignment 5!`{{If you like, you can compare your solution with ours, which is in LEDIT.ANS.  A{listing starts on page 29 of your printed course notes.  Note that a single{procedure handles adding, deleting, and replacing lines.  Replacing is done by{first deleting, then adding a line.{{Your solution might be very different from ours, but if it passed all the{tests, consider it correct.{{Early in this course we used the generic package Integer_IO.  Let's now learn{how to write our own generic packages, procedures, and functions.{}b[ 490B488]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Recursion and Assignment 4{{@#The Format of an Ada Program@-Subprograms and Packages`{{@#Generic Instantiation and@0Access Types, User Defined Types,{@&Assignment 1@=and Derived Types{{@#Simple Declarations and Simple@+Exceptions, Text_IO, and{@&Attributes@?Assignment 5{{@#Operators, Control Constructs, and@#^>  GENERICS, TASKING, AND ASSIGNMENT 6`{@&Assignment 2{@LMore Records and Types{@#Records, Arrays, and Assignment 3{@LAdvanced Topics{}b[ 491B489]@DGENERICS{{It would be easy to write a package that creates a single stack of 10 Integers,{and lets us Push and Pop on it.  However, the code would be about the same{regardless of the size of the stack, and regardless of the type of objects on{the stack.  For example, a second package that creates a stack of 50 Dates{would look about the same.  We can write one^generic~package, and instantiate{it for any size and almost any type we need.  The specification is:{{@4^generic`{@7^Size : Positive;`{@7^type Dummy is private;`{@4^package Stack_Package is`{@7^procedure Push(Object : in Dummy);`{@7^function Pop return Dummy;`{@4^end Stack_Package;`{{Since both Size and type Dummy are generic, both must be specified when we{instantiate the package:{{@'^package Stack_Of_10_Integers is new Stack_Package(10, Integer);`{@'^package Stack_Of_50_Dates@$is new Stack_Package(50, Date);`{}b[ 492B490]If the generic part says^type Dummy is private;~then the subprogram or package{body may do only three things with objects of type Dummy: create them, assign{them, and test them for equality or inequality.  Note that this is similar to{the list of things we may do with a private type^outside~an ordinary package.{In this case, we're listing what we can do^inside~the generic package.  Calling{the package's subprograms isn't on our list, because they're not written yet!{We're listing the things we can do when we write the body of the package.  Of{course, once we write some subprograms, other subprograms can call them.{{Although we can do only three things with objects of a private type inside a{generic package, we can instantiate that package with almost any type at all.{Our Stack_Package can be instantiated for Dates, Strings (see the next{paragraph), Rainbow_Colors, Floats, and any type for which we can assign{objects and test them for equality.  That means any type except a limited type.{We can't instantiate Stack_Package for type Text_IO.File_Type (a limited{private type), or for task types (discussed later), because in our package{we're allowed to assign and test for equality objects of type Dummy.{{Since we can't create objects of an unconstrained array type, if we want to{instantiate Stack_Package for Strings, we must use a constrained subtype of{String.  For example, we could write^subtype Name is String(1 .. 30);~and then{write^package Stack_Of_50_Names is new Stack_Package(50, Name);`.{}b[ 493B491]We could instantiate our package even for limited types like Text_IO.File_Type{if the generic part had said^type Dummy is limited private;`.  However, the only{thing our package could do with objects of that type is create them.{Ordinarily, that's not very useful.{{If the generic part says^type Dummy is ( <> );~then we can instantiate the{package (or subprogram) for any discrete type.  That means any enumeration or{integer type: Character, Boolean, Counter, No_Of_Apples, etc.  Inside the{package, attributes like 'First are available.{{If the generic part says^type Dummy is range <>;~then we can instantiate for{any integer type.  Inside the package, we can do things that can be done with{all integer types, such as add, etc.{{If the generic part says^type Dummy is delta <>;~then we can instantiate for{any fixed point type, to be discussed in the section on More Records and Types.{{Finally, if the generic part says^type Dummy is digits <>;~then we can{instantiate for any floating point type, such as Float or the Real we created.{}b[ 494B492]In Ada 9X, some additional forms are allowed.  If the generic part says^type{Dummy( <> ) is private;~then we can instantiate with unconstrained types like{String, provided that the body initializes any objects it creates of that type.{{If the generic part says^type Dummy is tagged private;~then we can instantiate{with any tagged type, to be covered in the section on More Records and Types.{{If the generic part says^type Dummy is new X;~or^type Dummy is new X with{private;~then we can instantiate with type^X~or with any type derived from^X`.{If^with private~is included, then we must instantiate with a tagged type.{{In all cases above, we can follow^Dummy~with^( <> )~to allow instantiating with{unconstrained types.  The body must initialize any objects it creates with an{unconstrained type.  We can also replace^is~in the generic part with^is private`{to allow instantiating with abstract types, to be covered later.{{If the generic part says^type Dummy is mod <>;~then we can instantiate with any{modular type, to be covered in the section on More Records and Types.{{Finally, if the generic part says^with package Dummy is new P( <> );~where^P~is{the name of a generic package, then we can instantiate with any package that we{obtained by instantiating^P`.{}b[ 495B493]The specification of a generic subprogram must be given separately from the{body.  For example, we can't eliminate the highlighted line in this function:{{@(generic{@+type Dummy_Float is digits <>;{@+type Dummy_Vector is array (Integer range <>) of Dummy_Float;{@'^function Sum(V : in Dummy_Vector) return Dummy_Float;`{@(function Sum(V : in Dummy_Vector) return Dummy_Float is{@+Answer : Dummy_Float := 0.0;{@(begin{@+for I in V'Range loop{@.Answer := Answer + V(I);{@+end loop;{@+return Answer;{@(end Sum;{}b[ 496B494]We can instantiate Sum and call it as follows:{{@/^type Vector is array(Integer range <>) of Float;`{@/^V1 : Vector(1 .. 10);`{@/^X  : Float;`{@/^function Sumv is new Sum(Float, Vector);`{@0...{@/^X := Sumv(V1);`{}b[ 497B495]@)generic{@,type Dummy is range <>;{@)procedure Display(Item : in Dummy);{{@)type No_Of_Apples is new Integer;{@)type Counter is range 0 .. 1_000_000;{@)type Answer is (Yes, No, Maybe);{@)procedure Display_Apples@#is new Display(No_Of_Apples);  -- 1{@)procedure Display_Counters is new Display(Counter);@'-- 2{@)procedure Display_Answers  is new Display(Answer);@(-- 3{{{@)Which commented line in the above program segment is^illegal`?{}Please press 1, 2, or 3, or B to go back.[349814992500B496]@)generic{@,type Dummy is range <>;{@)procedure Display(Item : in Dummy);{{@)type No_Of_Apples is new Integer;{@)type Counter is range 0 .. 1_000_000;{@)type Answer is (Yes, No, Maybe);{@)procedure Display_Apples@#is new Display(No_Of_Apples);  -- 1{@)procedure Display_Counters is new Display(Counter);@'-- 2{@(^procedure Display_Answers  is new Display(Answer);@(-- 3`{{{%You're right!~ When the generic part says^type Dummy is range <>;`, the{procedure may be instantiated for any integer type.  Answer is a discrete type,{but not an integer type.{{In the Advanced Topics section, we'll show an example of a generic function.{}q[ 501B497Q497]@)generic{@,type Dummy is range <>;{@)procedure Display(Item : in Dummy);{{@)type No_Of_Apples is new Integer;{@)type Counter is range 0 .. 1_000_000;{@)type Answer is (Yes, No, Maybe);{@)procedure Display_Apples@#is new Display(No_Of_Apples);  -- 1{@)procedure Display_Counters is new Display(Counter);@'-- 2{@)procedure Display_Answers  is new Display(Answer);@(-- 3{{{No, when the generic part says^type Dummy is range <>;`, the procedure may be{instantiated for any integer type.  No_Of_Apples is a type derived from{Integer, so it's an integer type.{}q[ 501B497Q497]@)generic{@,type Dummy is range <>;{@)procedure Display(Item : in Dummy);{{@)type No_Of_Apples is new Integer;{@)type Counter is range 0 .. 1_000_000;{@)type Answer is (Yes, No, Maybe);{@)procedure Display_Apples@#is new Display(No_Of_Apples);  -- 1{@)procedure Display_Counters is new Display(Counter);@'-- 2{@)procedure Display_Answers  is new Display(Answer);@(-- 3{{{No, when the generic part says^type Dummy is range <>;`, the procedure may be{instantiated for any integer type.  The definition of the user-defined type{Counter has the word^range`, so Counter is an integer type.{}q[ 501B497Q497]@DTASKING{{Here are two versions of a program with two parallel tasks.  Since the main{program is a task, these two versions are equivalent.{{@)with Text_IO; use Text_IO;@)with Text_IO; use Text_IO;{@)procedure Task_Demo is@0procedure Task_Demo is{@+^task A;~@:^task A;`{@+^task body A is~@3^task body A is`{@+^begin~@<^begin`{@.^Put_Line("b");~@3^Put_Line("a");`{@.^Put_Line("b");~@3^Put_Line("a");`{@+^end A;~@;^end A;`{@)begin@@^task B;`{@+^Put_Line("a");~@3^task body B is`{@+^Put_Line("a");~@3^begin`{@)end Task_Demo;@:^Put_Line("b");`{@Q^Put_Line("b");`{@N^end B;`{@Lbegin{@Onull;{@Lend Task_Demo;{}b[ 502B497]Our program could have specified as many tasks as we like.  Also, our tasks{could have declarations between^task body ... is~and^begin`.  If the computer{has several processors, and the Ada compiler makes use of that fact, the tasks{could actually run simultaneously.  Otherwise, the compiler may (but doesn't{have to) write code to^time slice~among the tasks, making them^appear~to run{simultaneously.  One implementation of Ada we tried time slices, and the output{of the program looked something like this:{{ab{{ab{{{This happened because Put_Line is equivalent to Put plus New_Line, and thus{Put_Line can get interrupted before the CR-LF is output.  Here one task{displayed "a", the other task displayed "b", and then both tasks sent CR-LF.{{Another implementation of Ada we tried won't time-slice unless told to with a{%pragma`, covered in the Advanced Topics section.  So the output of the same{program with that implementation of Ada looked like this:{}b[ 503B501]a{a{b{b{{In this case one task ran to completion before the other task started.  The{point is that both implementations of Ada ran our program correctly, but with{different results.{{When data is passed between tasks, we often don't want the process interrupted.{For example, suppose one task updates a record with several fields, such as a{Date.  Another task reads the record.  We don't want the second task to{interrupt the first in the middle of updating a record.  Otherwise, the second{task might read an updated Day field, an updated Month field, and an old Year{field, which would be meaningless.  Ada has an elegant solution to this{problem, called the^rendezvous`.{{In this example, we assume that the main program created both procedure Caller{and task Server, and defined type Date:{}b[ 504B502]@&procedure Caller is@*task Server is{@)D : Date;@4entry Update(Item : in out Date);{@Cend Server;{@&begin@8task body Server is{@(^-----;~@3begin{@(^-----;  -- Block 1~@)^-----;  -- Block 3`{@(^-----;~@5^-----;`{@E^accept Update(Item : in out Date) do`{@(^Server.Update(D);~@-^-----;  -- Block 4`{@H^-----;`{@(^-----;~@5^end Update;`{@(^-----;  -- Block 2~@)^-----;  -- Block 5`{@(^-----;~@5^-----;`{@&end Caller;@2end Server;{{Code blocks 1 and 3 run in parallel (perhaps simultaneously, as discussed).{Then Caller waits at the call to Server.Update while Server executes block 4.{Block 4 is called the critical section of code, where records might be updated,{etc.  When this^rendezvous~is over, blocks 2 and 5 run in parallel.  If Caller{reaches the call before Server reaches^accept`, Caller will wait patiently{there for Server.  If Server reaches^accept~first, it will wait patiently there{for a caller.{}b[ 505B503]@&procedure Caller is@*task Server is{@)D : Date;@3^entry~Update(Item : in out Date);{@Cend Server;{@&begin@8task body Server is{@)-----;@4begin{@)-----;  -- Block 1@+-----;  -- Block 3{@)-----;@7-----;{@E^accept~Update(Item : in out Date)^do`{@(^Server.Update(D);~@.-----;  -- Block 4{@I-----;{@)-----;@7end Update;{@)-----;  -- Block 2@+-----;  -- Block 5{@)-----;@7-----;{@&end Caller;@2end Server;{{The call to Update looks like a procedure call.  We can't^use~a task, so the{call requires dot notation.  The^entry~specification looks like a procedure{specification, with^entry~replacing^procedure`.  The task specification may have{any number of^entry~statements; if it has none, we write simply^task Server;`.{The^accept~block looks like a procedure without declarations, but^accept`{replaces^procedure`, and^do~replaces^is begin`.  An^accept~with no parameters{and no statements may be written simply as^accept Update;`.{}b[ 506B504]In Ada 9X there's another way, simpler than the rendezvous, to assure that one{task won't try to read an item while another task is writing it.  It's called{a^protected~object.  For example:{{@$type Date is ...@4^protected body~Prot_Date^is`{@$...@Efunction Read return Date is{@#^protected~Prot_Date^is~@1begin{@'function Read return Date;@.return Item;{@'procedure Write(D : in Date);@(end Read;{@#^private~{@'Item : Date;@9procedure Write(D : in Date) is{@#^end~Prot_Date;@:begin{@OItem := D;{@Lend Write;{@H^end~Prot_Date;{{The syntax is similar to a package or a task, and the calls to Read and Write{are similar to task calls:^D : Date;~...^D := Prot_Date.Read;~...{%Prot_Date.Write(D);`.  Ada 9X guarantees that calls to the protected{subprograms, in this case Read and Write, won't execute simultaneously.{{This is a protected^object`.  We'll learn about Ada 9X protected^types~shortly.{}b[ 507B505]@-procedure Master is@.task Slave is{@Qentry Sync;{@Nend Slave;{@Ntask body Slave is{@-begin@<begin{@0-----;@;-----;{@0-----;  -- Block 1@/-----;  -- Block 3{@0-----;@;-----;{@0Slave.Sync;@6accept Sync;{@0-----;@;-----;{@0-----;  -- Block 2@/-----;  -- Block 4{@0-----;@;-----;{@-end Master;@6end Slave;{{{True or False?  Statements in blocks 1 and 4 could execute simultaneously.{}Please press T for true or F for false, or B to go back.[F508T509B506]@-procedure Master is@.task Slave is{@Qentry Sync;{@Nend Slave;{@Ntask body Slave is{@-begin@<begin{@0-----;@;-----;{@0-----;  -- Block 1@/-----;  -- Block 3{@0-----;@;-----;{@/^Slave.Sync;~@4^accept Sync;`{@0-----;@;-----;{@0-----;  -- Block 2@/-----;  -- Block 4{@0-----;@;-----;{@-end Master;@6end Slave;{{{%You're right!~ Master will wait patiently at^Slave.Sync~for Slave to reach{%accept`, or Slave will wait patiently at^accept~for Master to reach{%Slave.Sync;`.  Therefore, blocks 1 and 4 can't execute simultaneously.{}q[ 510B507Q507]@-procedure Master is@.task Slave is{@Qentry Sync;{@Nend Slave;{@Ntask body Slave is{@-begin@<begin{@0-----;@;-----;{@0-----;  -- Block 1@/-----;  -- Block 3{@0-----;@;-----;{@0Slave.Sync;@6accept Sync;{@0-----;@;-----;{@0-----;  -- Block 2@/-----;  -- Block 4{@0-----;@;-----;{@-end Master;@6end Slave;{{{False.  Master will wait patiently at^Slave.Sync~for Slave to reach^accept`, or{Slave will wait patiently at^accept~for Master to reach^Slave.Sync;`.{Therefore, blocks 1 and 4 can't execute simultaneously.{}q[ 510B507Q507]If several tasks call an entry before the server reaches^accept`, the calls are{queued first-in, first-out.{{We can write a^select~block to accept any of several different calls:{{@8^select`{@<accept A;{@8^or`{@<accept B(I : in Integer) do{@?-----;{@<end B;{@8^or`{@<accept C;{@8^end select;`{{When^select~is reached, the task waits for a call to A or B or C.  If calls to{more than one entry are pending, one will be chosen arbitrarily.{{A^delay~statement, used in ordinary code, will delay a specified number of{seconds (plus any system overhead).  For example,{}b[ 511B507]@CA;{@B^delay 5.0;`{@CB;{{will call A, delay five seconds (plus system overhead), and then call B.{However, when used in a^select~block, the meaning is a bit different.  It's{used to implement an^impatient server`.  For example,{{@@^select`{@Daccept A;{@@^or`{@Daccept B;{@@^or`{@C^delay 5.0;`{@DC;{@@^end select;`{{will wait up to five seconds for a call to A or B.  If no call is received, C{will be called.{{%Guards~can be used to switch alternatives of a^select~block on and off.  For{example,{}b[ 512B510]@@J : Integer;{@@...{@?^select`{@B^when J = 1 =>`{@Caccept A;{@?^or`{@B^when J = 2 =>`{@Caccept B;{@?^end select;`{{Here A is an alternative only if the condition (J = 1) is true; B is an{alternative only if J = 2.  If J /= 1, then no call to A will be accepted, even{if one is pending.  If every branch of a^select~block has a guard and all{guards are false, Program_Error is raised.{}b[ 513B511]In Ada 9X, we have^protected types`.  For example:{{ ^protected type~P^is~@-^protected body~P^is`{@$^entry~One;@7^entry~One^when~X > Y^is`{@$^entry~Two(I : in Integer);@'^begin`{ ^private~@@...{@%X, Y : Integer;@2^end~One;{@%...{ ^end~P;@>^entry~Two(I : in Integer)^when~True^is`{@F^begin`{@J...{@F^end~Two;{@C^end~P;{{We can declare^Q : P;  J : Integer;~and then call^Q.One;~and^Q.Two(J);`.  In the{body, each entry has a^barrier`, similar to the guards discussed earlier.  Here{a call to One can be accepted only if X > Y; otherwise, the call is queued.  A{call to Two can always be accepted because the barrier is simply True.  At the{end of each call, all the barriers are re-evaluated.{{An entry can requeue itself on another entry.  For example, the body of Two can{execute^requeue One;~to requeue itself on entry One.{}b[ 514B512]Ada 9X also lets us write{{@?^select`{@B^delay 10.0;`{@CC;{@?^then abort`{@CA;{@CB;{@?^end select;`{{Here if the statements in the second block (the calls to A and B) take more{than 10.0 seconds, they are abandoned and the first block (the call to C) is{executed instead.{{Tasks "die" in three ways.  The least elegant way is for a task to^abort~it,{e.g.,^abort Server;`.  This is drastic, because Server might be doing anything.{A better way is for a family of tasks each to include^terminate;~as one{alternative in a^select~block.  (A "family" of tasks is the set of tasks{created by one "parent," for example, the main program.)  When calls to the{entries in the tasks all cease, all tasks in the family will reach the{%terminate~alternative, and all will die together.{}b[ 515B513]But the most orderly way for a task to die is for it simply to reach its last{statement.  For example, task T below will continue to accept calls to T.A and{T.B until a task calls T.Shutdown.  At that time, T will die.{{@+task T is@6task body T is{@.entry A;@6^Done : Boolean := False;`{@.entry B;@4begin{@-^entry Shutdown;~@.^while not Done loop`{@+end T;@>^select`{@Saccept A do{@V-----;{@Send A;{@O^or`{@Saccept B do{@V-----;{@Send B;{@O^or`{@R^accept Shutdown;`{@R^Done := True;`{@O^end select;`{@L^end loop;`{@Jend T;{}b[ 516B514]Trying to call an entry of a task that has died will raise Tasking_Error.{Also, a task can't terminate until all the tasks it creates terminate.  In{particular, the main program can't return to the operating system until all{tasks in the program have died.  Programmers must be careful to avoid possible{deadlocks.  Ada solves many problems that plague other languages, but{unfortunately the deadlock problem remains unsolved.{{A^select~block may have an^else~alternative.  Here's an example of a very{impatient server.  If a call to A or B is pending it will be served, otherwise,{C will be called:{{@@^select`{@Daccept A do{@G-----;{@Dend A;{@@^or`{@Daccept B do{@G-----;{@Dend B;{@@^else`{@DC;{@@^end select;`{}b[ 517B515]type Date is ...@5task body Data_Protector is{task Data_Protector is@2Save_D : Date;{@#entry Read_Date(D : out Date);@'Done@#: Boolean := False;{@#entry Write_Date(D : in Date);@$begin{@#entry Shutdown;@6accept Write_Date(D : in Date) do{end Data_Protector;@8Save_D := D:{@Hend Write_Date;{@Hwhile not Done loop{@Kselect{@Naccept Read_Date(D : out Date) do{@QD := Save_D;{@Nend Read_Date;{@Kor{@Naccept Write_Date(D : in Date) do{@QSave_D := D;{True or False?  This task must@0end Write_Date;{serve at least one call to@1or{Write_Date before it will@5accept Shutdown;{accept calls to Read_Date.@4Done := True;{@Kend select;{@Hend loop;{@Eend Data_Protector;{}Please press T for true or F for false, or B to go back.[T518F519B516]type Date is ...@5task body Data_Protector is{task Data_Protector is@2Save_D : Date;{@#entry Read_Date(D : out Date);@'Done@#: Boolean := False;{@#entry Write_Date(D : in Date);@$begin{@#entry Shutdown;@5^accept Write_Date(D : in Date) do`{end Data_Protector;@7^Save_D := D:`{@G^end Write_Date;`{@Hwhile not Done loop{@Kselect{@M^accept Read_Date(D : out Date) do`{@P^D := Save_D;`{@M^end Read_Date;`{@Kor{@M^accept Write_Date(D : in Date) do`{@P^Save_D := D;{You're right!~ The extra^accept~@-^end Write_Date;`{block outside the loop forces us@+or{to call Write_Date at least once@.accept Shutdown;{before we can call Read_Date.@1Done := True;{@Kend select;{@Hend loop;{@Eend Data_Protector;{}q[ 520B517Q517]type Date is ...@5task body Data_Protector is{task Data_Protector is@2Save_D : Date;{@#entry Read_Date(D : out Date);@'Done@#: Boolean := False;{@#entry Write_Date(D : in Date);@$begin{@#entry Shutdown;@6accept Write_Date(D : in Date) do{end Data_Protector;@8Save_D := D:{@Hend Write_Date;{@Hwhile not Done loop{@Kselect{@Naccept Read_Date(D : out Date) do{@QD := Save_D;{@Nend Read_Date;{@Kor{@Naccept Write_Date(D : in Date) do{@QSave_D := D;{True.  The extra^accept~block@1end Write_Date;{outside the loop forces us to@.or{call Write_Date at least once@1accept Shutdown;{before we can call Read_Date.@1Done := True;{@Kend select;{@Hend loop;{@Eend Data_Protector;{}q[ 520B517Q517]The^select~block can be used in a caller as well as a server.  The following{block waits up to five seconds to call entry A in task T.  If T isn't ready to{accept the call in five seconds, the block calls procedure B instead.  This is{called an impatient customer:{{@@^select`{@C^T.A;`{@@^or`{@C^delay 5.0;`{@C^B;`{@@^end select;`{{A very impatient customer can be implemented with^else`.  This block calls T.A{only if T is ready to accept the call immediately, otherwise, it calls B.{{@A^select`{@D^T.A;`{@A^else`{@D^B;`{@A^end select;`{}b[ 521B517]Task^types~may be declared.  This permits us to create an array of tasks, and{it lets us bring tasks into existence via access types.  Tasks begin executing{as soon as they're brought into existence.  For example,{{@;^task type X is`{@>^entry E;`{@;^end X;`{@;^type P is access X;`{@;^X1 : P;`{@;^A : array(1 .. 10) of X;`{@;^task body X is`{@?...{@;^end X;`{{Entries to these tasks are called thus:{{@;^A(5).E;`{@;^X1 := new X;`{@;^X1.all.E;~or just^X1.E;`{}b[ 522B520]Ada comes with a package Calendar; the specification is in section 9.6 of the{LRM.  The part that concerns us here is shown below.  Type Duration is a fixed{point type built into Ada; the^delay~statement discussed earlier takes an{object of type Duration.{{@'^package Calendar is`{@*^type Time is private;`{@*^function Clock return Time;`{@*^function "+"(Left : Time; Right : Duration) return Time;`{@*^function "-"(Left : Time; Right : Time)@%return Duration;`{@+...{@'^end Calendar;`{{Not shown are a few other operators, and subprograms to convert between type{Time and the year, month, day, and number of seconds since midnight.{{Let's write a program segment, using Calendar, that calls A every five seconds:{}b[ 523B521]@6^with Calendar; use Calendar;`{@7...{@6^Next_Event : Time := Clock + 5.0;`{@7...{@6^loop`{@9^delay Next_Event - Clock;`{@9^A;`{@9^Next_Event := Next_Event + 5.0;`{@6^end loop;`{{Note that this loop accounts for the time required to call A.  Instead of{delaying 5.0, we calculate the time of the next call in Next_Event, and delay{that time minus the current time, which we obtain by calling Clock.  Thus the{program will go through the loop once every 5.0 seconds, even if it takes a{little time to call A.  In Ada 9X, we may write^delay until Next_Event;~which{guarantees that no higher-priority task will interrupt the calculation of{Next_Event - Clock, thereby causing the delay to be too long.{{The^-~and^+~operators in this example all use infix functions from Calendar.{{We're now ready for Outside Assignment 6!  It will be much simpler than Outside{Assignment 5.{}b[ 524B522]@3OUTSIDE ASSIGNMENT 6 - EXERCISE IN TASKING{{On page 33 of your printed course notes is a listing of^TASKING.DUM`.  This{program calls a task entry to display^Tick!~on the screen every five seconds{until it has been displayed nine times.{{Every time^delay~is executed, the message^(5-second delay)~is displayed so that{the delay will be visible on the screen.  The program is entirely in lower{case, because your assignment is to modify it.  If you make your modifications{in upper case, it will be easy to see what you have changed.{{We want you to change the declaration of T from a single task to an^array~of{three tasks.  The tasks are numbered 1, 2, and 3.  Task 1 is to be activated{every^two~five-second intervals.  Task 2 is to be activated every^three~five-{-second intervals, and task 3, every^four`.  Also, instead of displaying^Tick!`,{each task will identify itself by number, for example,^Task number 3 is{starting`.  Output should look as shown on page 35 of your printed notes.{}b[ 525B523]We recommend that you create an array of three counters.  Each counter counts{down from its period (2, 3, or 4) to zero by one count every interval.  When a{counter reaches zero, the corresponding task entry is called, and the counter{is reset to its period.  All three counters should be initialized to zero, so{that all three tasks display their messages immediately upon activation of the{program.  You should use the rendezvous mechanism to inform each task of its{number (1, 2, or 3).  Your program should use a loop to do an orderly shutdown{of all three tasks at the end.{{Here are the steps to follow for Outside Assignment 6.  They're also in your{printed course notes on page 34:{}b[ 526B524]1.  Make a copy of TASKING.DUM by typing^COPY TASKING.DUM TASKING.ADA`.{@$Compile, link, and execute the program to make sure it displays^Tick!~nine{@$times, with a 5-second delay after each "Tick."{{2.  Edit TASKING.ADA to become your solution.  Make your changes in upper case.{{3.  Compile TASKING.ADA, link, and execute.{{4.  Compare your output with page 35 of the printed course notes.  If there are{@$any errors, go back to step 2.{{5.  When your output agrees with the printed course notes, you've finished the{@$assignment and will have a chance to compare your solution with ours.{{{Please type X to exit^ADA-TUTR~temporarily, and try Outside Assignment 6.  Work{at your own pace; there's no deadline.  Good luck!{}Please type X to exit, a space to go on, or B to go back.[ 527B525]@-^Congratulations on Completing Outside Assignment 6!`{{If you like, you can compare your solution with ours, which is in TASKING.ANS.{A listing is on page 36 of your printed course notes.  Your solution might be{different from ours, but if your^output~agrees with page 35 of the printed{notes, your solution is correct.{{You've learned a great deal of Ada!  Let's go on to discuss some more records{and types.{}b[ 528B526]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Recursion and Assignment 4{{@#The Format of an Ada Program@-Subprograms and Packages`{{@#Generic Instantiation and@0Access Types, User Defined Types,{@&Assignment 1@=and Derived Types{{@#Simple Declarations and Simple@+Exceptions, Text_IO, and{@&Attributes@?Assignment 5{{@#Operators, Control Constructs, and@'Generics, Tasking, and Assignment 6`{@&Assignment 2{@H^>  MORE RECORDS AND TYPES`{@#Records, Arrays, and Assignment 3{@LAdvanced Topics{}b[ 529B527]@3RECORD DISCRIMINANTS AND RECORD VARIANTS{{The definition of a record type can have^discriminants`, which have the same{form as formal parameters ("dummy arguments") of subprograms, except that the{mode is omitted.  Default values may be supplied.  For example,{{@'type Matrix is array(Integer range <>, Integer range <>) of Float;{@'type Square_Matrix%(Size : Positive := 9)~is{@*record{@-Sq : Matrix%(1 .. Size, 1 .. Size)`;{@*end record;{{Although objects of type Matrix can be rectangular, objects of type{Square_Matrix must be square.  In declaring these objects, we use the same{syntax as a subprogram call, with either positional or named notation:{{@#^A : Square_Matrix(7);  -- a 7-by-7 matrix`{@#^B : Square_Matrix(Size => 5);  -- a 5-by-5 matrix`{@#^C : Square_Matrix;  -- a 9-by-9 matrix, using the default value of Size`{}b[ 530B528]Of course, subtypes of discriminated records can be declared.  For example,{{@/^subtype Chess_Board is Square_Matrix(Size => 8);`{{A record discriminant is used in the definition of type Text in the{Text_Handler package specification of section 7.6 of the Ada 83 LRM:{{@2Maximum : constant := ... ;{@2subtype Index is Integer range 0 .. Maximum;{@2...{@1^type Text(Maximum_Length : Index) is`{@4^record`{@7^Pos@#: Index := 0;`{@7^Value : String(1 .. Maximum_Length);`{@4^end record;`{{With the simplified version of type Text presented earlier, every object of{type Text occupied enough memory for the longest string we expected to handle{(e.g., 80 characters).  With this version, each object of type Text that we{create can have just the Maximum_Length we need, and its effective length Pos{can vary from zero to that Maximum_Length.  The record discriminant complicates{the package specification only very slightly; see the Ada 83 LRM, section 7.6.{}b[ 531B529]The definition of a record type can have a^variant`, which also has the same{form as a subprogram formal parameter without the mode.  However, the syntax of{a^case~construct is used to specify part of the record.  Although a record can{have several discriminants, it can have only one variant, and the variant part{must appear last in the record.  For example,{{@8type Sex_Type is (Male, Female);{@8type Person%(Sex : Sex_Type)~is{@;record{@>Age : Natural;{@=^case Sex is`{@@^when Male =>`{@C^Bearded  : Boolean;`{@@^when Female =>`{@C^Children : Natural;`{@=^end case;`{@;end record;{{If the sex of the person is Male, we want the record to include a Boolean{showing whether he's bearded, but if the sex is Female, we want the record to{include an Integer (subtype Natural), showing the number of children she has.{}b[ 532B530]@8type Sex_Type is (Male, Female);{@8type Person(Sex : Sex_Type) is{@;record{@>Age : Natural;{@>case Sex is{@Awhen Male =>{@DBearded  : Boolean;{@Awhen Female =>{@DChildren : Natural;{@>end case;{@;end record;{{Objects are declared and given values as we'd expect:{{  ^John : Person(Sex => Male) := (Sex => Male, Age => 21, Bearded => False);`{  ^Mary : Person(Sex => Female) := (Sex => Female, Age => 18, Children => 0);`{{Attempting to reference John.Children or Mary.Bearded will raise{Constraint_Error.  Subtypes may be declared as follows:{{@7^subtype Man is Person(Male);`{@7^subtype Woman is Person(Female);`{}b[ 533B531]type Computer_Size is (Handheld,Notebook,Portable,Desktop,Mainframe,Cluster);{type Computer(Size : Computer_Size) is{@#record{@&K_Mem : Positive;{@&Disks : Natural;{@&case Size is{@)when Cluster =>{@,Number_Of_Units : Positive;{@,Data_Rate@': Float;{@)when others =>{@,null;{@&end case;{@#end record;{My_PC@': Computer(Desktop) := (Desktop, K_Mem => 4096, Disks => 2);  ^-- 1`{Company_LAN : Computer(Cluster) := (Cluster, K_Mem => 24576, Disks => 8); ^-- 2`{{Which commented declaration in the above program is^illegal`?{}Please press 1 or 2, or B to go back.[25341535B532]type Computer_Size is (Handheld,Notebook,Portable,Desktop,Mainframe,Cluster);{type Computer(Size : Computer_Size) is{@#record{@&K_Mem : Positive;{@&Disks : Natural;{@&case Size is{@)when Cluster =>{@,Number_Of_Units : Positive;{@,Data_Rate@': Float;{@)when others =>{@,null;{@&end case;{@#end record;{My_PC@': Computer(Desktop) := (Desktop, K_Mem => 4096, Disks => 2);@#-- 1{%Company_LAN : Computer(Cluster) := (Cluster, K_Mem => 24576, Disks => 8);  -- 2`{{%You're right!~ The initialization of Company_LAN fails to include fields for{Number_Of_Units and Data_Rate.{}q[ 536B533Q533]type Computer_Size is (Handheld,Notebook,Portable,Desktop,Mainframe,Cluster);{type Computer(Size : Computer_Size) is{@#record{@&K_Mem : Positive;{@&Disks : Natural;{@&case Size is{@)when Cluster =>{@,Number_Of_Units : Positive;{@,Data_Rate@': Float;{@)when others =>{@,null;{@&end case;{@#end record;{My_PC@': Computer(Desktop) := (Desktop, K_Mem => 4096, Disks => 2);@#-- 1{Company_LAN : Computer(Cluster) := (Cluster, K_Mem => 24576, Disks => 8);  -- 2{{No, the declaration of My_PC and its initialization are correct.  When Size is{Desktop, the^others~clause of the^case~applies, so there are no Number_Of_Units{and Data_Rate fields in this case.{}q[ 536B533Q533]@4TAGGED RECORDS AND DYNAMIC DISPATCHING{{In Ada 9X, a record may be^tagged`.  This allows us later to derive a new type{from the original and add fields.  For example, if Day_Of_Week_Type is suitably{declared along with Day_Subtype and Month_Type, Ada 9X lets us write{{@5type Date is^tagged`{@8record{@;Day@#: Day_Subtype;{@;Month : Month_Type;{@;Year  : Integer;{@8end record;{{@5type Complete_Date is^new~Date^with`{@8record{@;Day_Of_Week : Day_Of_Week_Type;{@8end record;{{Now objects of type Date have three fields: Day, Month, and Year, but objects{of type Complete_Date have four fields: Day, Month, Year, and Day_Of_Week.{}b[ 537B533]If we want to derive a new type without adding any new fields, we write, for{example,{{@2type New_Date is^new~Date^with null record;`{{If a tagged record is to be a private type, the declaration in the package{specification contains the words^tagged private`, like this:{{@9type Date is^tagged private`;{{The actual structure of the record is declared in the private part of the{package specification exactly as any other tagged record:{{@9private{@<...{@<type Date is^tagged`{@?record{@BDay@#: Day_Subtype;{@BMonth : Month_Type;{@BYear  : Integer;{@?end record;{}b[ 538B536]We can convert objects of a derived type to the parent type.  For example, if{we have^CD : Complete_Date;~we can write^Date(CD)`.  This is useful in making{software reusable.  For example, suppose we have written a procedure to Display{a Date:{{@8procedure Display(D : in Date);{{If we now wish to write a procedure to Display a Complete_Date, we could call{on the procedure we've already written.  If the above procedure and the{associated types are defined in package P, we could write:{{@)with Text_IO, P; use P;{@)procedure Display(CD : in Complete_Date) is{@,-- Call previous procedure to display the first 3 fields.{@+^Display(Date(CD));`{@,-- Now display the fourth field.{@,Text_IO.Put_Line(Day_Of_Week_Type'Image(CD.Day_Of_Week));{@)end Display;{{Thus the procedure to display a Date was reused when we wrote the procedure to{display a Complete_Date.{}b[ 539B537]Although type Date and the types derived from it are all different types, we{can refer to all the types collectively as^Date'Class`.  The attribute^'Class`{can be applied to the name of any tagged type.  If we declare an object to be{of type^Date'Class`, we must initialize it so that the compiler will know the{exact type of the object.  The type of this object can't change at run time.{For example, if we write^D : Date'Class := Date'(12, Dec, 1815);~we can't later{write^D := Complete_Date'(4, Jul, 1776, Thu);`.  This would change the type of{the object D and make it grow larger by adding a new field, Day_Of_Week.  This{isn't permitted.{{However, we can declare an access type to Date'Class without being specific{about the exact type to be accessed:{{@8type Ptr is access^Date'Class`;{{Now objects of type Ptr can point to objects of type Date at one time and to{objects of type Complete_Date at another.  Also, we could build a linked list,{with some of the links of type Date and some of type Complete_Date.  This is{called a^heterogeneous~linked list.{}b[ 540B538]Let's suppose that we declare, in the specification for a package P, type Date{(a tagged record), type Complete_Date derived from Date with an extra field,{and two overloaded procedures Display, one to display a Date and one to display{a Complete_Date.  Suppose that the specification for P also includes the{definition for type Ptr:{{@8type Ptr is access^Date'Class`;{{Now suppose that our program, which^with`s and^use`s P, declares an array A of{two pointers of type Ptr.  Let A(1) point to a Date and A(2) point to a{Complete_Date.  The program to follow shows how the system will decide^at run{time~which of two overloaded versions of Display to call, depending on the type{of A(I).all:{}b[ 541B539]@$package P is{@'...{@'type Date is^tagged~record ...{@'type Complete_Date is^new~Date^with~record ...{@'type Ptr is access^Date'Class`;{@'procedure Display(D : in Date);{@'procedure Display(D : in Complete_Date);{@$end P;{{@$with P; use P;{@$procedure Dynamic_Dispatching_Demo is{@'A : array(1 .. 2) of Ptr;{@$begin{@'A(1) := new Date'(12, Dec, 1815);{@'A(2) := new Complete_Date'(4, Jul, 1776, Thu);{@'for I in A'Range loop{@*Display(%A(I).all`);  -- Decides at run time which Display to call.{@'end loop;{@$end Dynamic_Dispatching_Demo;{{This is called^dynamic dispatching~or^tagged type dispatching`, and is available{only in Ada 9X, not in Ada 83.{}b[ 542B540]In Ada 9X, the formal parameters ("dummy arguments") of a subprogram may also{be of a class-wide type.  For example, in a package that has defined both of{our Display procedures and the associated types, we can write:{{@)procedure Show(X : in^Date'Class`) is{@)begin{@,Display(%X`);  -- Decides at run time which Display to call.{@)end Show;{{It this case, the exact type of X is not known until run time, and can vary{from one call of Show to the next.  Therefore, the statement^Display(X);~will{decide at run time which version of Display to call.{{Related to this are^access parameters~in Ada 9X.  Instead of writing{{@6procedure Show(X :^in~Date'Class);{{we can write{{@4procedure Show(X :^access~Date'Class);{}b[ 543B541]@4procedure Show(X :^access~Date'Class);{{In this case, Show is no longer called with an object belonging to Date'Class{(that is, a Date or a Complete_Date), but rather with an object of any access{type pointing to objects belonging to Date'Class.  For example, we could now{call Show with an object of the type Ptr we defined earlier:{{@/D : Ptr := new Complete_Date(4, Jul, 1776, Thu);{@/Show(D);{{Show again decides at run time which version of Display to call, but now Show{must dereference the access value passed to it:{{@'procedure Show(X :^access~Date'Class) is{@'begin{@*Display(%X.all`);  -- Decides at run time which Display to call.{@'end Show;{}b[ 544B542]The^accessibility check~which we discussed earlier when we talked about access{types has to be performed at run time in the case of access parameters.  The{Ada 9X compiler automatically generates code to do this.  For access types{pointing to named objects, discussed earlier, the accessibility check is{performed at compile time.  In both cases the purpose of the accessibility{check is to insure that no object of an access type can ever point to an object{that no longer exists.{{Here's our sample tagged type dispatching program, rewritten to make use of{access parameters:{}b[ 545B543]@#package P is{@&...{@&type Date is tagged record ...{@&type Complete_Date is new Date with record ...{@&type Ptr is access Date'Class;{@&procedure Display(D : in Date);{@&procedure Display(D : in Complete_Date);{@%^procedure Show(X : access Date'Class);  -- Body calls Display(X.all);`{@#end P;{{@#with P; use P;{@#procedure Dynamic_Dispatching_Demo is{@&A : array(1 .. 2) of Ptr;{@#begin{@&A(1) := new Date'(12, Dec, 1815);{@&A(2) := new Complete_Date'(4, Jul, 1776, Thu);{@&for I in A'Range loop{@(^Show(A(I));`{@&end loop;{@#end Dynamic_Dispatching_Demo;{{Again, the^for~loop first displays a Date and then displays a Complete_Date.{}b[ 546B544]@4ABSTRACT TYPES AND ABSTRACT SUBPROGRAMS{{@+package P is{@.type Abstract_Date is^abstract~tagged null record;{@.procedure Display(%AD : in Abstract_Date`)^is abstract`;{@+end P;{{In this example for Ada 9X only, type Abstract_Date is an^abstract type`.  We{can't declare objects of that type, but we can derive other types from it.  For{example, we can derive type Date by adding three fields, and then derive type{Complete_Date from type Date by adding one more field.{{The^abstract procedure~does not have a body, only a specification.  However, it{lets us write procedures built around types derived from the abstract type.{For example, we could write overloaded procedures Display for types Date and{Complete_Date (these procedures will have bodies as well as specifications).{Also, by declaring an access type to type Abstract_Date, we could again make{use of dynamic dispatching to our overloaded versions of Display:{}b[ 547B545]@%package P is{@(type Abstract_Date is abstract tagged null record;{@(procedure Display(AD : in Abstract_Date) is abstract;{@%end P;{{@%with P; use P;{@%package Q is{@(...{@(type Ptr is access Abstract_Date;{@(type Date is new Abstract_Date with record ... -- Day, Month, Year{@(type Complete_Date is new Date with record ... -- Day_Of_Week{@(procedure Display(D : in Date);{@(procedure Display(CD : in Complete_Date);{@%end Q;{{The advantage of this is that we can write package P, with all its abstract{procedures, before we write the code in package Q detailing what the derived{types (Date and Complete_Date) look like.{}b[ 548B546]@3FIXED POINT, MODULAR, AND UNIVERSAL TYPES{{The only fixed point type defined in package Standard is Duration.  However,{Ada lets us define our own fixed point types.  We specify the accuracy with the{reserved word^delta`, and a range constraint is required.  For example,{{@/^type Voltage is delta 0.01 range -20.0 .. 20.0;`{{This guarantees that the objects of type Voltage will be represented with at{least an accuracy of 1/100.  Since the computer is binary, Ada will choose an{internal representation at least as accurate as 1/128.  It might use even{greater accuracy, for example, 1/256.  In any event, it's guaranteed that the{accuracy is at least as good as that requested.{{It's possible to make a request that a particular implementation of Ada can't{handle.  For example, if we write{{@.^type Voltage is delta 1.0E-10 range 0.0 .. 1.0E9;`{{the Ada compiler that we're using may have to report that it has no internal{representation that satisfies this requirement.  (Almost any^delta~would be{unreasonable if Ada didn't require range constraints on all fixed point types.){}b[ 549B547]@0type Voltage is delta 0.01 range -20.0 .. 20.0;{{The set of numbers that can be represented exactly by any Ada that accepts a{type definition like the above is called the^model numbers~of that type.  This{applies to floating types as well as fixed, for example,{{@4^type W is digits 5 range 0.0 .. 100.0;`{{A particular implementation may represent additional numbers exactly; these are{called^safe numbers`.  The safe numbers are a superset of the model numbers;{their range usually is a little larger.{{We can add and subtract objects of a fixed point type.  However, if we multiply{or divide them in Ada 83, we must immediately convert the result to the same or{another numeric type before we can store it.  For example,{{@,^V1, V2, V3 : Voltage;`{@-...{@,^V1 := V2 + V3;  -- legal`{@,^V1 := V2 * V3;  -- illegal in Ada 83, legal in Ada 9X`{@,^V1 := Voltage(V2 * V3);  -- legal`{}b[ 550B548]In Ada 9X, we can multiply two numbers of a fixed point type without an{explicit type conversion if the type of the multiply is uniquely determined.{In the previous example,{{@,^V1, V2, V3 : Voltage;`{@-...{@,^V1 := V2 * V3;  -- illegal in Ada 83, legal in Ada 9X`{{the multiplication is legal in Ada 9X because storing the result into V1{uniquely determines the type of the product of V2 and V3.{{Note that^V1 := V1 * V2 * V3~is illegal because the intermediate result has no{uniquely determined type.{{Also note that if we have^procedure Display(V : in Voltage);~then in Ada 9X we{can write{{@>^Display(V2 * V3);`{{because the type of V2 * V3 is uniquely determined by the procedure call.{{Text_IO contains a generic package Fixed_IO for I/O of fixed point types.{}b[ 551B549]Ada 9X also provides^modular types`.  These are unsigned integers, and the{arithmetic is performed modulo a specified number so that overflow can never{occur.  For example, in Ada 9X we can write:{{@7^type Unsigned_Byte is mod 256;`{{The modulus doesn't have to be a power of two, but it often is.  If we now{declare^A : Unsigned_Byte := 100;~and^B : Unsigned_Byte := 200;~then the result{of^A + B~will be 300 mod 256, or 44.{{In Ada 9X, the package^Interfaces~is supplied, and it defines a modular type{for each signed integer type.  For example, an implementation of Ada 9X might{define the types^Unsigned_8`,^Unsigned_16`, and^Unsigned_32`.  Type^Unsigned_8`{corresponds to the example^Unsigned_Byte~above.{}b[ 552B550]When we declare a variable in Ada, we give its type.  But when we declare a{constant, we may or may not give its type.  For example,{{@3^L  : constant Integer := 30;`{@3^M  : constant := 1000;`{@3^E  : constant Float := 2.718281828;`{@3^Pi : constant := 3.141592654;`{{Also, when we write a number, such as 3.0 or 29_999, we usually don't qualify{it with a type (for example,^Float'(3.0)`).{{Suppose an implementation of Ada provides types Integer, Long_Integer, Float,{and Long_Float.  How can Ada determine the types of M, Pi, 3.0, and 29_999?  M{and 29_999 are said to be of type^universal_integer`; they can assume any{integer type as required.  Pi and 3.0 are said to be of type^universal_real~and{can assume any floating or fixed point type as required.{{We can't explicitly declare objects to be of universal types.  However, we can{write{}b[ 553B551]@9M  : constant := 1000;{@9Pi : constant := 3.141592654;{@8^I  : Integer;`{@8^LI : Long_Integer;`{@8^F  : Float;`{@8^LF : Long_Float;`{@9...{@8^I := M;  LI := M;`{@8^I := 29_999;  LI := 29_999;`{@8^F := Pi;  LF := Pi;`{@8^F := 3.0;  LF := 3.0;`{{and in each case the constant assumes the correct type.  The result of{multiplying or dividing two numbers of a fixed point type is said to be of type{%universal_fixed`.  This result must be explicitly converted to some numeric{type before it can be stored.{{Most of the attributes that produce integer results, like^Pos`, are of type{universal_integer.  For example, with the declarations above, we could write{{@:^I  := Character'Pos('A');`{@:^LI := Character'Pos('A');`{}b[ 554B552]Which one of the following declarations is^illegal`?{{{@.1.@#type Rate is digits 6;{{@.2.@#type Distance is digits 6 range 0.0 .. 1.0E6;{{@.3.@#type Current is delta 0.1;{{@.4.@#type Temp is delta 0.05 range -200.0 .. 450.0;{}Please press 1, 2, 3, or 4, or B to go back.[3555155625574558B553]@.1.@#type Rate is digits 6;{{@.2.@#type Distance is digits 6 range 0.0 .. 1.0E6;{{@-^3.@#type Current is delta 0.1;`{{@.4.@#type Temp is delta 0.05 range -200.0 .. 450.0;{{{%You're right!~ A fixed point type declaration must have a range constraint.{}q[ 559B554Q554]@.1.@#type Rate is digits 6;{{@.2.@#type Distance is digits 6 range 0.0 .. 1.0E6;{{@.3.@#type Current is delta 0.1;{{@.4.@#type Temp is delta 0.05 range -200.0 .. 450.0;{{{No, number 1 is legal.  A user defined floating point type need not have a{range constraint.{}q[ 559B554Q554]@.1.@#type Rate is digits 6;{{@.2.@#type Distance is digits 6 range 0.0 .. 1.0E6;{{@.3.@#type Current is delta 0.1;{{@.4.@#type Temp is delta 0.05 range -200.0 .. 450.0;{{{No, number 2 is legal.  A user defined floating point type may have a range{constraint.{}q[ 559B554Q554]@.1.@#type Rate is digits 6;{{@.2.@#type Distance is digits 6 range 0.0 .. 1.0E6;{{@.3.@#type Current is delta 0.1;{{@.4.@#type Temp is delta 0.05 range -200.0 .. 450.0;{{{No, number 4 is legal.  A fixed point type declaration must have a range{constraint.{}q[ 559B554Q554]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Recursion and Assignment 4{{@#The Format of an Ada Program@-Subprograms and Packages`{{@#Generic Instantiation and@0Access Types, User Defined Types,{@&Assignment 1@=and Derived Types{{@#Simple Declarations and Simple@+Exceptions, Text_IO, and{@&Attributes@?Assignment 5{{@#Operators, Control Constructs, and@'Generics, Tasking, and Assignment 6{@&Assignment 2{@LMore Records and Types{@#Records, Arrays, and Assignment 3{@H^>  ADVANCED TOPICS`{}b[ 560B554]@DRENAMING{{A subprogram can be renamed in Ada.  This allows us to avoid the dot notation{without a^use~clause.  For example, if our program^with`s Text_IO, we can write:{{@(^procedure Print(Object : in String) renames Text_IO.Put_Line;`{{We can now call Print instead of Text_IO.Put_Line.  The old name is still{available.  Note that renaming can change the names of the formal parameters{("dummy arguments").  Renaming can also add, delete, or change default values.{When used in a package, a renaming declaration like the above goes in the{%specification`, not the body.  In Ada 9X, the specification can say simply{%procedure Print(Object : in String);`, and the package^body~can supply the body{of Print with the^renames~declaration above.{{We can also rename task entries as procedures.  This is the only way to avoid{the dot notation when calling a task entry.{{A function can be renamed as an infix operator, if it has the right number and{types of parameters.  Also, an infix operator can be renamed as a function.{For example, earlier we defined type Vector and wrote:{}b[ 561B559]@-^function "*"(Left, Right : in Vector) return Float;`{{This could be renamed as follows:{{@'^function Dot_Product(X, Y : in Vector) return Float renames "*";`{{Renaming can get around the restriction that library subprograms can't be infix{operators.  We can use a normal function name for the library, and rename it as{an infix operator for our program.  Similarly, we can get around the rule that{library subprograms can't overload each other.  We can give subprograms{distinct names in the library, and rename them in our program to overload each{other.{{An attribute that takes a parameter, such as^Pred~and^Succ`, can be renamed as a{function.  Record components can be renamed.  If^D~is of the type^Date~we had{earlier, we can write^J : Integer renames D.Year;`.  Exceptions can also be{renamed, as in^No_Such_File : exception renames Text_IO.Name_Error;`.{{A subtype can be used to achieve the effect of renaming a type, for example,{%subtype File is Text_IO.File_Type;`.{}b[ 562B560]@:PACKAGES STANDARD AND ASCII{{Ada comes with a package Standard.  However, unlike all the other packages,{Standard is needed by^every~Ada compilation unit.  Therefore, Standard is{automatically^with`ed and^use`d in every compilation.  It need not be mentioned{in a context clause.  Standard contains the definitions built into the Ada{language, such as^type Boolean is (False, True);`.  A listing of the package{specification is in Appendix C of the LRM.  Thus, the full name for the type{Boolean is Standard.Boolean, the full name for Integer is Standard.Integer,{etc.  Naturally, this normally need not concern the programmer.  The dot{notation is automatic because Standard is automatically^use`d in every{compilation.{{However, inside package Standard is a package ASCII.  Since this package is{part of Standard, we never have to write a^with~clause for it.  But ASCII isn't{automatically^use`d.  If we want the dot notation for ASCII to be automatic, we{have to provide a^use~clause.  As the listing in the LRM shows, ASCII contains{names for all the unprintable ASCII characters, such as BEL, ESC, etc.  It also{provides names for many punctuation marks, in case your terminal or printer{doesn't have them.  For example, Dollar, At_Sign, etc.  Finally, it provides{names for all lower case letters, from LC_A to LC_Z.{}b[ 563B561]For example, either of the following programs will display^a$b~and ring the{bell or beep the terminal:{{@'with Text_IO; use Text_IO;{@'procedure Ab is{@'begin{@*Put_Line(%ASCII.LC_A & ASCII.Dollar & ASCII.LC_B & ASCII.BEL`);{@'end Ab;{{@'with Text_IO; use Text_IO;{@'procedure Ab is{@)^use ASCII;`{@'begin{@*Put_Line(%LC_A & Dollar & LC_B & BEL`);{@'end Ab;{{Note the placement of^use ASCII;~in the second example.  It's similar to the{placement of^use My_Int_IO;~in ADD.ADA, which we discussed early in the course.{}b[ 564B562]@8AN ALTERNATIVE TO INFIX NOTATION{{Earlier we learned to define and use infix operators like{{@.type Vector is array(Integer range <>) of Float;{@-^function "*"(Left, Right : in Vector) return Float;`{@.A, B : Vector(1 .. 10);{@.F@$: Float;{@....{@-^F := A * B;`{{An alternative notation equivalent to^F := A * B;~is^F := "*"(A, B);`.  Why{would anyone want to use this clumsier notation?  If our function is in a{package Math that the calling program^with`s but for some reason doesn't^use`, we{could use dot notation and write^F := Math."*"(A, B);`.  But we couldn't use dot{notation directly with infix operators, as in F := A Math.* B; or even{F := A Math."*" B;.  Both of those are illegal.  The alternative notation can{also be used to emphasize that an operator comes from package Standard.  For{example, if I, J, and K are Integers, we could write^I := Standard."*"(J, K);`,{which is equivalent to^I := J * K;`.{}b[ 565B563]Assuming X, Y, and Z have been declared Float, which one of the following is{%illegal`?{{@:1.  X := Y / Z;{{@:2.  X := Y Standard."/" Z;{{@:3.  X := Standard."/"(Y, Z);{}Please press 1, 2, or 3, or B to go back.[256615673568B564]@:1.  X := Y / Z;{{@9^2.  X := Y Standard."/" Z;`{{@:3.  X := Standard."/"(Y, Z);{{{%You're right!~ The syntax of number 2 is illegal.  To specify the package{Standard, we have to use the syntax of number 3.  Normally, of course, the{syntax of number 1 is used.{}q[ 569B565Q565]@:1.  X := Y / Z;{{@:2.  X := Y Standard."/" Z;{{@:3.  X := Standard."/"(Y, Z);{{{No, number 1 is the syntax that would ordinarily be used for division, and is{legal.{}q[ 569B565Q565]@:1.  X := Y / Z;{{@:2.  X := Y Standard."/" Z;{{@:3.  X := Standard."/"(Y, Z);{{{No, number 3 is the correct way to specify package Standard explicitly.{}q[ 569B565Q565]@@MORE ATTRIBUTES{{Ada provides a wide variety of attributes.  All of them are listed and defined{in Appendix A of the LRM.  The most important ones that we haven't yet{discussed are these:{{%First~and^Last~can be used with any scalar type or subtype (including floating{and fixed), not just discrete types and subtypes.  For example,^Float'Last~is{the highest number your particular Ada represents with type Float.{{For any real type or subtype (floating or fixed),^Small~and^Large~are the{smallest and largest positive model numbers.  Thus^Float'Small~is the{difference between zero and the next larger number in type Float.  Also, for{any floating point (sub)type,^Epsilon~is the difference between^one~and the{next larger number.  We'll use^Epsilon~in a generic function later.{{For a floating point (sub)type,^Digits~returns the value given for^digits~in{the declaration, and for a fixed point (sub)type,^Delta~returns the value given{for^delta~in the declaration.  These attributes may not seem too useful,{because the programmer already knows what he or she wrote in the declarations.{However, they're useful in generic packages and subprograms.  For example, if{the generic part says^type Dummy is delta <>;`, the body can use^Dummy'Delta`.{}b[ 570B554]For any discrete (sub)type,^Width~gives the maximum length that the attribute{%Image~can produce. ^Boolean'Width~is 5 because "False" has length 5.  With our{earlier definition of Rainbow_Color,^Rainbow_Color'Width~is 6.  For versions of{Ada using 16-bit Integers,^Integer'Width~is also 6, the length of "-32768".{{%Count~is used with the name of a task entry.  It returns the number of calls{presently queued on the entry. ^Terminated~is of type Boolean.  It's used with{a task name, and tells if the task is terminated.{{Let's write a generic function to compute the square root for any floating{point type, using Newton-Raphson iteration.  This method simply says that if G{is a guess of the square root of X, the next guess is the average of G and X/G.{For example, if we want to compute the square root of 9.0 and our first guess{is 9.0, successive guesses are 5.0, 3.4, 3.02352941, 3.00009155, 3.00000000.{Note that convergence is very rapid.  However, the problem in writing a program{like this is knowing when to stop the iteration.  We'll use the attribute{%Epsilon`.  Since G*G/X should be 1.0, we'll quit when the absolute value of the{difference between G*G/X and 1.0 is less than or equal to 3.0 times Epsilon.{Recall that^Dummy'Epsilon~is the difference between 1.0 and the next higher{number for type Dummy.  If we use 1.0 times Epsilon, the loop might never{terminate, and if we use 10.0 times Epsilon, we might not get full precision.{So we'll use 3.0 times Epsilon.  Here's our function:{}b[ 571B569] ^generic`{@$^type Dummy is digits <>;`{ ^function Sqrt(X :in Dummy) return Dummy;`{ ^function Sqrt(X :in Dummy) return Dummy is`{@$^Guess : Dummy := X;`{ ^begin`{@$^if X < 0.0 then`{@'^raise Constraint_Error;`{@$^end if;`{@$^while X /= 0.0 and then abs(Guess*Guess/X - 1.0) > 3.0*Dummy'Epsilon loop`{@'^Guess := (X/Guess + Guess) * 0.5;`{@$^end loop;`{@$^return Guess;`{ ^end Sqrt;`{{We tested our Sqrt with an implementation of Ada having types Float,{Long_Float, and Long_Long_Float.  The last gives at least 33 decimal digits of{precision.  Sqrt was instantiated for all three floating point types, as was{Float_IO to display the results.  When tested with the three types, all{displayed digits of the answers were correct.{}b[ 572B570]@:SEQUENTIAL_IO AND DIRECT_IO{{Text_IO creates, reads and writes text files that can be typed on the screen or{printed.  Ada also provides packages^Sequential_IO~and^Direct_IO,~which create,{read, and write binary files.  These files usually can't be typed or printed,{but they tend to be more efficient than text files, because the computer{doesn't have to convert numbers between its internal representation and ASCII{to read and write binary files.{{Sequential_IO and Direct_IO are both generic, and can be instantiated for any{type.  The specifications are in sections 14.2.3 and 14.2.5 of the LRM.  Like{Text_IO, they have procedures to Create, Open, and Close files, but the I/O{procedures are called Read and Write, rather than Put, Get, Put_Line, and{Get_Line.  Sequential_IO always reads and writes sequentially, but Direct_IO is{capable of random access.  In Direct_IO, an optional extra parameter in Read{and Write tells the procedure the position in the file to read From or write{To.{{Text_IO and instantiations of Sequential_IO and Direct_IO each define their^own`{File_Type, so we can't open a file with one package and then do I/O with{another.  Direct_IO provides a File_Mode of Inout_File as well as the usual{In_File and Out_File.{}b[ 573B571]If you like, you can examine the file ADA_TUTR.ADA for an example of the use of{Direct_IO. ^ADA-TUTR~creates a subtype for a block of characters and then{instantiates Direct_IO for that subtype.  It then opens ADA_TUTR.DAT with mode{In_File so that it can read blocks of characters by random access.  This{enables^ADA-TUTR~to find and display any screen quickly.  The preliminary{comments in ADA_TUTR.ADA describe the format of the data file ADA_TUTR.DAT in{detail.{{You may also want to examine the files DAT2TXT.ADA and TXT2DAT.ADA.  These two{programs are used when installing^ADA-TUTR~on non-PC computers.  Their use is{described on pages 42-43 of your printed course notes.  They^with~both Text_IO{and Direct_IO, because they access a text file as well as a random access file.{However, to avoid confusion between the two packages, they^use~neither Text_IO{nor the instantiation of Direct_IO.  Dot notation is used instead.{}b[ 574B572]Which commented line is^illegal`?{{@$with Text_IO, Sequential_IO; use Text_IO, Sequential_IO; ^-- 1`{@$procedure IO is{@'subtype Line is String(1 .. 80);{@'type Screen is array(1 .. 24) of Line;{@'package Line_IO is new Sequential_IO(Line); use Line_IO; ^-- 2`{@'package Screen_IO is new Sequential_IO(Screen); use Screen_IO; ^-- 3`{@$begin{@'null;{@$end IO;{}Please press 1, 2, or 3, or B to go back.[157525763577B573]@#^with Text_IO, Sequential_IO; use Text_IO, Sequential_IO;  -- 1`{@$procedure IO is{@'subtype Line is String(1 .. 80);{@'type Screen is array(1 .. 24) of Line;{@'package Line_IO is new Sequential_IO(Line); use Line_IO;  -- 2{@'package Screen_IO is new Sequential_IO(Screen); use Screen_IO;  -- 3{@$begin{@'null;{@$end IO;{{%You're right!~ We can't^use~a generic package, only its instantiations,{because we can't call the subprograms in a generic package.  The first line{should read{{@/^with Text_IO, Sequential_IO; use Text_IO;  -- 1`{}q[ 578B574Q574]@$with Text_IO, Sequential_IO; use Text_IO, Sequential_IO;  -- 1{@$procedure IO is{@'subtype Line is String(1 .. 80);{@'type Screen is array(1 .. 24) of Line;{@'package Line_IO is new Sequential_IO(Line); use Line_IO;  -- 2{@'package Screen_IO is new Sequential_IO(Screen); use Screen_IO;  -- 3{@$begin{@'null;{@$end IO;{{No, the instantiation of Sequential_IO for the subtype Line is correct.{}q[ 578B574Q574]@$with Text_IO, Sequential_IO; use Text_IO, Sequential_IO;  -- 1{@$procedure IO is{@'subtype Line is String(1 .. 80);{@'type Screen is array(1 .. 24) of Line;{@'package Line_IO is new Sequential_IO(Line); use Line_IO;  -- 2{@'package Screen_IO is new Sequential_IO(Screen); use Screen_IO;  -- 3{@$begin{@'null;{@$end IO;{{No, the instantiation of Sequential_IO for the type Screen is correct.{}q[ 578B574Q574]@6SUBPROGRAM PARAMETERS WITH GENERICS{{The generic part of a subprogram or package can specify a dummy^subprogram~as{well as a dummy^type`.  This is similar to using subprograms as parameters{in Algol and Pascal, and to using the little-known keyword EXTERNAL in Fortran.{In Ada, we simply precede the dummy subprogram specification with the keyword{%with~in the generic part.  This use of the word^with~has nothing to do with{context clauses.  Here's the specification of a generic function that has one{dummy function specification in the generic part:{{^generic`{@#^with function Dummy(X : in Float) return Float;`{^function Definite_Integral(Lower_Limit, Upper_Limit : in Float) return Float;`{{We could then write a function Cos, instantiate Definite_Integral for it, and{use the instantiation as follows:{{^Answer : Float;`{^function Cos(X : in Float) return Float;`{^function Definite_Integral_Of_Cos is new Definite_Integral(Cos);`{ ...{^Answer := Definite_Integral_Of_Cos(Lower_Limit => 0.0, Upper_Limit => 1.5708);`{}b[ 579B574]generic{  ^with function Dummy(X : in Float) return Float;`{function Definite_Integral(Lower_Limit, Upper_Limit : in Float) return Float;{{function Definite_Integral(Lower_Limit, Upper_Limit : in Float) return Float is{@#Mult : array(0 .. 6) of Float := (1.0, 4.0, 2.0, 4.0, 2.0, 4.0, 1.0);{@#Sum  : Float := 0.0;{@#X@$: Float;  -- the independent variable{begin{@#for I in 0 .. 6 loop{@&X@#:= Lower_Limit + (Float(I) / 6.0) * (Upper_Limit - Lower_Limit);{@&Sum := Sum + Mult(I) *^Dummy(X)`;{@#end loop;{@#return Sum * (Upper_Limit - Lower_Limit) / 18.0;{end Definite_Integral;{{This is one possible body for the generic function Definite_Integral.  (The{specification is repeated for reference.)  This function integrates the{function Dummy between the two limits by evaluating Dummy at seven points and{using Simpson's rule.  (Definite_Integral could be improved by making the{number of points a generic parameter, instead of fixing it at seven.){}b[ 580B578]@7REPRESENTATION CLAUSES AND SYSTEM{{Ada normally represents an enumeration type internally with successive integers{starting at zero.  For example, if we write{{@0^type Command is (Left, Right, Forward, Back);`{{the compiler will normally represent Left with 0, Right with 1, etc.  Usually{this doesn't concern the programmer.  However, after the above declaration, we{can specify the internal representation with a^representation clause~like this:{{@&^for Command use (Left => 1, Right => 2, Forward => 4, Back => 8);`{{We might want to do that if, for example, we're sending a value of type Command{to some hardware which will interpret the bit patterns.  The values must be{assigned in increasing order with no duplications, but gaps are permitted.  The{attributes Succ, Pred, Pos, and Val are^not~affected.  Thus^Command'Pos(Back)`{is still 3.{{We can specify the^Size`, in bits, of the objects of a given type:{}b[ 581B579]@9^type Num is range 0 .. 100;`{@9^for Num'Size use 8;`{{We can specify the^Storage_Size~for a task type and for a collection of{%access`ed objects like a linked list.  If^Monitor~is a task and the{specification for our linked list says^type P is access Link;`, we can write{{@5^for Monitor'Storage_Size use 16_384;`{@5^for P'Storage_Size use 32_768;`{{The attributes Size and Storage_Size can also be used in the usual way:{{@5^I : Integer := Monitor'Storage_Size;`{{We can specify the attribute Small for a fixed point type:{{@/^type Voltage is delta 0.01 range -20.0 .. 20.0;`{@/^for Voltage'Small use 1.0/128.0;`{{Before discussing the remaining types of representation clauses, we must{briefly mention the package^System~that comes with Ada. ^System~contains{implementation dependent specifications.{}b[ 582B580]A brief outline of package System is in section 13.7 of the LRM.  However, the{full package specification should appear in the documentation that came with{your compiler.  For all compilers that meet the Ada Standard, the description{of implementation dependent features (including the specification of package{System) is always in Appendix F of the documentation.  Of interest here is the{type Address.  In our examples, we'll assume that System.Address is some{integer type.  (Under DOS, type System.Address may be a bit more complicated.){{Representation clauses can use the reserved word^at~followed by a constant of{type System.Address to specify the absolute address of a variable, a constant,{a task entry, a procedure, or a package.  The package System must be visible.{This feature is useful for memory-mapped I/O and interrupt handlers, etc.  For{example:{{@5Modem_Control : Integer;{@4^for Modem_Control use at 16#7C00#;`{@5task Interrupt_Handler is{@8entry Clock_Interrupt;{@7^for Clock_Interrupt use at 16#100#;`{@5end Interrupt_Handler;{@5procedure Keystroke;{@4^for Keystroke use at 16#200#;`{}b[ 583B581]Finally, we can use^at`,^mod`, and^range~to specify how records are stored.{For example,{{@3type Very_Short_Integer is range 0 .. 15;{@3type Packed is{@6record{@9A, B, C, D : Very_Short_Integer;{@6end record;{@2^for Packed use`{@5^record at mod 2;`{@8^A at 0 range 0 .. 3;`{@8^B at 0 range 4 .. 7;`{@8^C at 1 range 0 .. 3;`{@8^D at 1 range 4 .. 7;`{@5^end record;`{{This forces A and B to be stored in bits 0 .. 3 and 4 .. 7 of byte 0 of the{record, and C and D to be packed into byte 1.  The optional clause^record at{mod 2;~specifies that all records of type Packed will begin at even addresses.{{An implementation of Ada need not accept most representation clauses to meet{the standard.  If any clause is rejected, an error message will be displayed.{}b[ 584B582]@0type Answer is (Yes, No, Maybe);{@0for Answer use (Yes => 1, No => 2, Maybe => 4);{{What is Answer'Val(2)?{{{1.  Answer'Val(2) is No.{{2.  Answer'Val(2) is Maybe.{}Please press 1 or 2, or B to go back.[25851586B583]@/^type Answer is (Yes, No, Maybe);`{@0for Answer use (Yes => 1, No => 2, Maybe => 4);{{{%You're right!~ The representation clause doesn't affect the attributes Pos and{Val, and positions are numbered from zero.  So^Answer'Val(2)~is^Maybe`.{}q[ 587B584Q584]@0type Answer is (Yes, No, Maybe);{@0for Answer use (Yes => 1, No => 2, Maybe => 4);{{{No, the representation clause doesn't affect the attributes Pos and Val, and{positions are numbered from zero.  So Answer'Val(2) is Maybe.{}q[ 587B584Q584]@0UNCHECKED CONVERSION AND UNCHECKED DEALLOCATION{{Ada comes with a generic function^Unchecked_Conversion~and a generic procedure{%Unchecked_Deallocation`.  They can be instantiated for any type.  Both are{somewhat dangerous to use, but we'll describe them briefly.  Their{specifications are:{{@+^generic`{@.^type Source is limited private;`{@.^type Target is limited private;`{@+^function Unchecked_Conversion(S : SOURCE) return Target;`{{@+^generic`{@.^type Object is limited private;`{@.^type Name@#is access Object;`{@+^procedure Unchecked_Deallocation(X : in out Name);`{{Unchecked_Conversion "converts" from one type to another without doing any{arithmetic or bit manipulation.  In other words, it lets us look at an object{of one type as if it were of another type.  The effect is similar to the use{of EQUIVALENCE in Fortran.  The results may be unpredictable unless the two{types occupy the same amount of storage.{}b[ 588B584]One use of Unchecked_Conversion might be to allow us to^and~two Integers.  Some{Ada compilers come with a package that enables us to do that, but many{compilers have no such package.  Suppose that types Integer and Boolean occupy{the same amount of storage.  If our program says^with Unchecked_Conversion;~we{could write{{@%^function Int_To_Bool is new Unchecked_Conversion(Integer, Boolean);`{@%^function Bool_To_Int is new Unchecked_Conversion(Boolean, Integer);`{@%^function "and"(Left, Right : in Integer) return Integer is`{@%^begin`{@(^return Bool_To_Int(Int_To_Bool(Left) and Int_To_Bool(Right));`{@%^end "and";`{{Using Unchecked_Conversion usually destroys program portability.{{Unchecked_Deallocation allows us to free the memory occupied by an object{associated with a pointer.  Normally, the system reclaims memory when it's{needed.  However, the execution time for that so-called^garbage collection`{tends to be long and unpredictable.  Suppose we have^type P is access Link;~and{%Head : P;`.  Also suppose that we no longer need the object pointed to by Head`,{and we're sure that no other pointer points to the same object as Head.  If our{program says^with Unchecked_Deallocation;~we can write{}b[ 589B587]@,^procedure Free is new Unchecked_Deallocation(Link, P);`{@-...{@,^Free(Head);`{{This will release the memory occupied by the object pointed to by^Head`, and{then set^Head~to^null`.  But there's a danger.  If there's another pointer that{pointed to the same object, it now points to released memory.  A reference to{that pointer will have unpredictable results.  In general, it's best to let the{system handle the reclaiming of memory.  That way there's no danger of dangling{references.{}b[ 590B588]@DPRAGMAS{{A^pragma~is a message to the compiler.  The pragmas that are predefined by Ada{are all described in Appendix B of the LRM; we'll discuss the most important{ones here.  A particular implementation of Ada need not honor all the{predefined pragmas, and it may add some of its own.  (One implementation of Ada{adds a pragma Time_Slice, used with tasking.)  Unlike representation clauses,{unimplemented predefined pragmas do^not~cause error messages; the compiler{simply ignores them.  This enhances program portability.  Any additional{pragmas added by a particular implementation of Ada will be explained in{Appendix F of the compiler documentation.  The most important predefined{pragmas are these:{{The statements^pragma List(On);~and^pragma List(Off);~turn on and off the{compiler listing.  Also,^pragma Page;~will cause the compiler listing to start{a new page, if the listing is turned on.  These pragmas are allowed almost{anywhere in the program.{{Within the declarative region we can write^pragma Optimize(Time);~or^pragma{Optimize(Space);~to ask the compiler to optimize the program for minimum{execution time or minimum memory usage.{}b[ 591B589]We can write^pragma Inline(`...%);~with the name of a subprogram to ask the{compiler to write inline code in place of every call to the subprogram.  Even{implementations of Ada that honor this pragma will ignore it if the subprogram{is recursive.{{We can call a subprogram written in another language by writing^pragma{Interface(`...%,~...%);~after the subprogram specification.  The two arguments are{the name of the language and the subprogram name.  Consult the compiler{documentation for information on bringing the object file into the Ada library.{Pragma Interface is used primarily in Ada 83.  Ada 9X replaces pragma Interface{with^pragma Import~and adds^pragma Export~to allow a program written in another{language to call an Ada subprogram.  Unlike pragma Interface, these two Ada 9X{pragmas can be used to share objects as well as subprograms.  Ada 9X also adds{%pragma Convention~to specify that objects of a type should be stored using the{conventions of another language.  Pragmas Import and Export take three{arguments: the name of the language, the Ada name of the subprogram or object,{and an optional external linker name for the subprogram or object.  Pragma{Convention takes two arguments: the name of the language and the Ada name of{the type whose storage convention is being specified.{}b[ 592B590]We can ask the compiler to minimize memory occupied by a record or array by{writing, after the type declaration,^pragma Pack(`...%);~with the name of the{type.  Note that the specification for package Standard (in Appendix C of the{LRM) contains^pragma Pack(String);~after the definition of type String.{{Package System defines a subtype of Integer called Priority.  We can assign a{priority to a task by writing, in the specification,^pragma Priority(`...%);~with{an argument of subtype System.Priority.  Higher numbers denote greater urgency.{{The pragma^Suppress~can be used to ask the compiler to turn off certain checks,{such as Constraint_Error.  It's dangerous and shouldn't be used unless{absolutely necessary because of time or memory constraints.{}b[ 593B591]In the author's opinion, which one of these is^not~dangerous?{{{@61.  Unchecked_Deallocation{{@62.  pragma Pack{{@63.  pragma Suppress{}Please press 1, 2, or 3, or B to go back.[259415953596B592]@61.  Unchecked_Deallocation{{@5^2.  pragma Pack`{{@63.  pragma Suppress{{{%You're right!~ The worst^pragma Pack~could do is slow the program down, and{this pragma is used in package Standard.  Unchecked_Deallocation could allow a{pointer to point to memory that has been released, with unpredictable results.{Pragma Suppress could allow a program to use a subscript that's out of range,{etc.{}q[ 597B593Q593]@61.  Unchecked_Deallocation{{@62.  pragma Pack{{@63.  pragma Suppress{{{No, Unchecked_Deallocation is dangerous because it could allow a pointer to{point to memory that has been released, with unpredictable results.{}q[ 597B593Q593]@61.  Unchecked_Deallocation{{@62.  pragma Pack{{@63.  pragma Suppress{{{No, pragma Suppress is dangerous because it could allow a program to use a{subscript that's out of range, etc.{}q[ 597B593Q593]@<LOOSE ENDS AND PITFALLS{{In this final section, we cover some miscellaneous topics that were omitted{earlier for simplicity.  We also mention some common errors made by Ada{programmers.  If you're a beginner, you aren't expected to understand every{paragraph until you've gained more experience, so we won't ask questions in{this section.{{Some terminals and printers don't support the entire ASCII character set.  In{an Ada program, the vertical bar^|~may be replaced with the exclamation mark^!`,{as in^when 3 ! 5 =>`.  Also, a pair of sharp signs^#~may be replaced with a pair{of colons^:`, as in^16:7C03:`.  The quotation marks around a string constant may{be replaced with percent signs if the string doesn't contain any quotation{marks.  In that case, any percent signs within the string must be doubled.{These character replacements shouldn't be used in programs if the equipment{will support the standard characters.{{An expression is called^static~if it can be evaluated at compile time.  In{almost every case where a constant normally appears, a static expression may{also be used.  For example, an address representation clause normally takes{a constant of type System.Address.  A static expression of this type is also{acceptable, as in^for Clock_Interrupt use at 16*16;`.{}b[ 598B593]The unary minus is always an operator and never part of a constant.  Thus^-5`{is actually a static expression and not a constant.  Normally, this doesn't{concern the programmer, because, as we just said, static expressions can{usually appear where a constant appears.  However, in a few special situations{we can get into trouble.  For example, in Ada 83 we can write{%for I in 10 .. 20 loop~and^A : array(10 .. 20) of Float;~but we can't omit the{words^Integer range~in^for I in Integer range -10 .. 10 loop~and{%A : array(Integer range -10 .. 10) of Float;`!  (Ada 9X lets us write these{without^Integer range`, however.){{Also, if a package P declares^type Count is new Integer;~then the unary minus{operator for that type is part of the package.  If our program^with`s but{doesn't^use~P, we can write^A : P.Count := 1;~but not^B : P.Count := -1;`.{We either have to^use~the package,^rename~P."-", or write{%B : P.Count := P."-"(1);`.  Because we sometines don't want to^use~the package{except to avoid writing^P."-"(1)`, Ada 9X lets us write{{@;with P;^use type P.Count`;{}b[ 599B597]@;with P;^use type P.Count`;{{This automatically^use`s only the infix operators belonging to the type{P.Count.  Other operators belonging to P.Count, and other identifiers in the{package P still require dot notation with the above^use type~clause.{{The operators have precedence, so that 1 + 2 * 3 means 1 + (2 * 3).  The{precedence of all the operators is given in section 4.5 of the LRM.  A{programmer should never have to look these up, because parentheses should be{used for any cases that aren't obvious.  Unary minus has a low precedence, so{%-A mod B~means^-(A mod B)`.{{If we write^A, B : array(1 .. 5) of Float;~then A and B have^different`{anonymous types, and we can't write^A := B;`.  To fix this, write{%type Vector5 is array(1 .. 5) of Float;~and then^A, B : Vector5;`.{{Ada will automatically convert from a universal type to a named type, but not{from a named type to a universal.  For example,{{@3^C1 : constant Integer := 1;  -- legal`{@3^C2 : constant Integer := 2;  -- legal`{@3^C3 : constant := C1 + C2;@$-- illegal`{}b[ 600B598]When arrays are assigned, the subscripts don't have to match; only the lengths{and types need match.  But in Ada 83 (not Ada 9X), if a formal parameter{("dummy argument") of a subprogram is a constrained array, the subscripts in{the call to the subprogram must match.  For example, the last line here will{raise Constraint_Error in Ada 83:{{@/^subtype Name is String(1 .. 30);`{@/^John : Name;`{@/^Line : String(1 .. 80);`{@/^procedure Display(Person : in Name);`{@0...{@/^John := Line(51 .. 80);@#-- legal`{@/^Display(Line( 1 .. 30));  -- legal`{@/^Display(Line(51 .. 80));  -- illegal in Ada 83`{}b[ 601B599]When a subprogram formal parameter is an^un`constrained array, beginners often{wrongly assume that the subscripts will start with one.  For example,{{@5^Line : String(1 .. 80);`{@5^procedure Display(S : in String) is`{@5^begin`{@8^for I in 1 .. S'Length loop`{@<...^S(I)~...{{This will raise Constraint_Error if we call^Display(Line(51 .. 80));`.  The^for`{statement should be changed to say^for I in S'Range loop`.{{Remember that elaboration occurs at run time.  The following raises{Program_Error by trying to activate a task before elaborating its body:{{@:^task type T is~...^end T;`{@:^type P is access T;`{@:^T1 : P := new T;`{@:^task body T is~...^end T;`{{The third line should be changed to^T1 : P;~and the statement^T1 := new T;`{should be placed in the executable region.{}b[ 602B600]Similarly, this procedure tries to activate a function before elaborating its{body.  The initialization of J should be moved to the executable region:{{@0^procedure Test is`{@3^function X return Integer;`{@3^J : Integer := X;  -- Raises Program_Error.`{@3^function X return Integer is`{@3^begin`{@6^return 5;`{@3^end X;`{@0^begin`{@3^null;`{@0^end Test;`{{A^return~statement in a function is used with an object:^return Answer;`.{However,^return~may also appear without an object in a^procedure`; we simply{write^return;`.  Normally, a procedure returns after executing its last{statement, but an early return is possible by this method.  Well structured{programs don't use this feature of Ada.{}b[ 603B601]Some implementations of Ada provide a package^Low_Level_IO~which includes{overloaded procedures^Send_Control~and^Receive_Control~to interface various{hardware devices directly.  This package is completely implementation{dependent, so you'll have to consult Appendix F of your compiler documentation.{{Many implementations of Ada allow you to insert^machine code~into a program.{Some implementations do this with a pragma, such as^pragma Native`, which can be{inserted in the middle of a procedure, function, etc.  Other implementations{provide a package called^Machine_Code~which usually contains a rather complex{record definition representing the format of a machine instruction.  In this{case, we can write a procedure or function that^with`s Machine_Code.  In place{of the usual Ada statements in the executable region, we write record{aggregates, each one representing a machine code instruction.  Since the method{of inserting machine code into a program varies from one implementation to the{next, you'll have to consult the compiler documentation.{}b[ 604B602]In the unusual case of a^for~loop index hiding an explicitly declared object of{the same name, the explicitly declared object^can~be referenced inside the{loop.  Simply use dot notation with the name of the compilation unit (function,{procedure, etc.)  For example, the following is legal:{{@;procedure Main is{@>Ix : Float;{@>J  : Integer;{@;begin{@>Ix := 3.2;{@>for Ix in 1 .. 10 loop{@@^Main.Ix~:= 6.0;{@AJ := Ix;{@>end loop;{@;end Main;{{%Inside~the loop,^Ix~refers to the loop index, and the explicitly declared{object can be referenced by writing^Main.Ix`. ^Outside~the loop,^Ix~refers to{the explicitly declared object, and the loop index doesn't exist.{}b[ 605B603]In the rare case of an aggregate containing just one element, we must use named{notation rather than positional notation.  For example, the last line is{illegal in the following program segment, because the right hand side is a{Float rather than an array of one Float.{{@0type Vector is array(Integer range <>) of Float;{@/^A : Vector(1 .. 1);`{@0...{@/^A := (1 => 2.3);  -- legal`{@/^A := (2.3);  -- illegal`{{It's OK to use positional notation in calls to subprograms with only one{parameter, for example,^Put_Line("Hello");`.{}b[ 606B604]Ada 9X includes seven^annexes`, described in Appendixes G through M of the Ada{9X LRM.  An Ada 9X compiler may implement any, all, or none of these.  Consult{appendixes G through M of your compiler documentation for details.  The{optional Ada 9X annexes are as follows:{{1. ^Systems Programming:~ Access to machine operations, interrupt support,{@$shared variable control, task identification, etc.{{2. ^Real-Time Systems:~ Dynamic task priorities, scheduling, dispatching,{@$queueing, monotonic time, etc.  An implementation that provides this must{@$provide Systems Programming as well.{{3. ^Distributed Systems:~ Multiple partitions of an Ada program executing{@$concurrently.{{4. ^Information Systems:~ Decimal types for handling monetary values.{@$"Picture" strings to simplify output of monetary amounts.{{5. ^Numerics:~ Complex numbers, improved accuracy requirements for floating-{@$-point arithmetic, random number generation, etc.{}b[ 607B605]6. ^Safety and Security:~ Adds requirements on compilers for safety-critical{@$systems.{{7. ^Interface to Other Languages:~ Features for writing mixed-language{@$programs.{}b[ 608B606]Well, we haven't covered^all~there is to know about Ada, but this has been a{very thorough course.  If you've come this far and completed the six Outside{Assignments, you should be a very good Ada programmer.  To be an excellent Ada{programmer, start doing all your casual programming in Ada.  If you need a{simple program to balance your checkbook, write it in Ada!  At this point,{switching to Ada for all your programming will do you much more good than{further instruction from a tutorial program.{{The best way to answer any remaining questions about Ada is to "ask the{compiler" by writing a brief test program, especially if your compiler is{validated.  You can also look in the LRM, which, by definition, does cover^all`{of the Ada language.  However, the LRM isn't easy reading!{{The best way to debug a short program is often to execute it by hand, with{pencil and paper.  You can also add extra statements to the program to display{intermediate results, and remove them later.{{We wish you success with Ada, and welcome your comments and suggestions!{{Now, you can press B to go back,{{@2or, for one last time ...{}@:... type a space to go on.[ 101B607]